ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

c++刷leetcode

2021-06-12 12:01:28  阅读:123  来源: 互联网

标签:head return nums int ret tail c++ leetcode


c++刷leetcode

**刷题目的: 熟练使用c++语法、STL组件的用法 **

count: 13

索引
1. 两数之和
15. 三数之和
16. 最接近的三数之和
589. N叉树的前序遍历
47. 全排列 II
124. 二叉树中的最大路径和
543. 二叉树的直径
448. 找到所有数组中消失的数字
283. 移动零
461. 汉明距离
17. 电话号码的字母组合
82. 删除排序链表中的重复元素 II
10. 正则表达式匹配

------------------------index-----------------------

1. 两数之和

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        vector<int> ret;
        unordered_map<int,int>pos_map;
        for (int i = 0; i < nums.size();++i)
        {
            if (pos_map.count(target-nums[i]))
            {
                ret.push_back(i);
                ret.push_back(pos_map[target-nums[i]]);
                return ret;
            }
            
            pos_map[nums[i]] = i;
        }
        return ret;
    }
};

**思路: **我们遍历数组nums,借助unordered_map做数组元素和其在数组中的位置的映射,每当我们遍历到一个数组成员,我们先查找unordered_map中是否存在与该元素相加,构成要求的target的元素,如果存在的话,那说明我们已经找到这两个元素,所以我们就可以通过他们的键得到他们的值,也即是他们在数组中的位置。

STL

unordered_map

  1. unordered_map 比map块,因为它不需要排序。尽管他们的范围遍历都是比较低效的。

  2. Unordered maps 可通过运算符[]来使用键key,直接访问其映射的 == > mp[key] = value;

  3. std::unordered_map::count ( )

    搜索unordered_map容器中key=k的成员的个数,由于unordered_map容器键是唯一的,所以在这个key存在的基础上,这个返回值永远为1.

15. 三数之和

C语言:

int compare(void *a,void *b)
{
    return *((int *)a) - *((int *)b);
}

/**
 * Return an array of arrays of size *returnSize.
 * The sizes of the arrays are returned as *returnColumnSizes array.
 * Note: Both returned array and *columnSizes array must be malloced, assume caller calls free().
 */
int** threeSum(int* nums, int numsSize, int* returnSize, int** returnColumnSizes){
    int **ret = NULL;
    int count = 0;
    int *retcol = NULL;
	
    (*returnSize) = count;
    (*returnColumnSizes) = retcol;

    if (!nums || numsSize <= 2)
    {
        return ret;
    }

	qsort(nums,numsSize,sizeof(int),(void *)compare);

	ret = (int **)realloc(ret,sizeof(int *)*numsSize*numsSize);
    retcol = (int *)realloc(retcol,sizeof(int)*numsSize*numsSize);

    for (int i = 0; i < numsSize-2;++i)
    {
        if (nums[i] > 0)
        {
            break;
        }
		
        if (i > 0 && nums[i] == nums[i-1] )
        {
            continue;
        }
		
        int head = i+1;
        int tail = numsSize-1;
        
        while (head < tail)
        {
            int target = nums[head] + nums[tail] + nums[i];
            if (target == 0)
            {
                #if 0
                在内部逐步扩展指针数组,会导致超时,真操蛋!
                ret = (int **)realloc(ret,sizeof(int *)*(count+1));
                retcol = (int *)realloc(retcol,sizeof(int)*(count+1));
                #endif
                
                retcol[count] = 3;
                ret[count] = (int *)malloc(sizeof(int)*3);
                
                ret[count][0] = nums[i];
                ret[count][1] = nums[head];
                ret[count][2] = nums[tail];

                ++count;

                while (head < tail && nums[head] == nums[head+1])
                {
                    ++head;
                }

                while (head < tail && nums[tail] == nums[tail - 1])
                {
                    --tail;
                }

                ++head;
                --tail;
            }
            else if (target < 0)
            {
                ++head;
            }
            else
            {
                --tail;
            }
        }
    }

    (*returnSize) = count;
    (*returnColumnSizes) = retcol;

    return ret;
}

c++:

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        const int size = (int)nums.size();
        vector<vector<int>> ret;

        if (size < 3)
        {
            return ret;
        }
        
        sort(nums.begin(),nums.end());

        for (int i = 0; i < size -2;++i)
        {
            if (nums[i] > 0)
            {
                break;
            }

            if (i > 0 && nums[i] == nums[i-1])
            {
                continue;
            }

            int head = i+1;
            int tail = size-1;

            while (head < tail)
            {
                int target = nums[i] + nums[head] + nums[tail];
                if (target == 0)
                {
                    ret.push_back({nums[i],nums[head],nums[tail]});

                    while (head < tail && nums[head] == nums[head+1])
                    {
                        ++head;
                    }

                    while (head < tail && nums[tail] == nums[tail-1])
                    {
                        --tail;
                    }

                    ++head;
                    --tail;
                }
                else if (target < 0)
                {
                    ++head;
                }
                else 
                {
                    --tail;
                }
            }
        }

        return ret;
    }
};

16. 最接近的三数之和

class Solution {
public:
    int threeSumClosest(vector<int>& nums, int target) {
        const int size = (int)nums.size();
        int mostequal = nums[0] + nums[1] + nums[2];
        int diff = abs(mostequal - target);

        sort(nums.begin(),nums.end());

        for (int i = 0; i < size -2;++i)
        {
            int head = i+1;
            int tail = size-1;

            while (head < tail)
            {
                int tmp = nums[i] + nums[head] + nums[tail];
                int tmpdiff = abs(target - tmp);
                if (diff > tmpdiff)
                {
                    diff = tmpdiff;
                    mostequal = tmp;
                }

                if (tmp < target)
                {
                    ++head;
                }
                else 
                {
                    --tail;
                }
            }
        }

        return mostequal;
    }
};

589. N叉树的前序遍历

class Solution {
public:
    vector<int> preorder(Node* root) {
        vector<int> ret;
        if (!root)
        {
            return ret;
        }
        stack<Node *>auxstack;
        auxstack.push(root);
        while (!auxstack.empty())
        {
            Node *ptmp = auxstack.top();
            ret.push_back(ptmp->val);
            auxstack.pop();
            
            for (auto itr = ptmp->children.rbegin();itr != ptmp->children.rend();++itr)
            {
                auxstack.push(*itr);
            }
        }

        return ret;
    }
};

STL

stack

在这里插入图片描述

47. 全排列 II

难度中等709收藏分享切换为英文接收动态反馈

给定一个可包含重复数字的序列 nums按任意顺序 返回所有不重复的全排列。

示例 1:

输入:nums = [1,1,2]
输出:
[[1,1,2],
 [1,2,1],
 [2,1,1]]

示例 2:

输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

提示:

  • 1 <= nums.length <= 8
  • -10 <= nums[i] <= 10

as


STL

istream

(1) 从输入流is获取string,直到遇到字符delim
istream& getline (istream& is, string& str, char delim);
istream& getline (istream&& is, string& str, char delim);

(2) 和(1)相比,默认delim为换行符’\n’
istream& getline (istream& is, string& str);
istream& getline (istream&& is, string& str);

注意事项:

1.delim字符并不作为输入保存

2.若执行getline之前,str中有内容,则将被is的输入所替换。

3.若is达到了文件结束状态,那么getline也会停止。

set

  1. set<int> var_set({1,2,3,4,5});var_set.find(2)返回的是指向这个元素的指针,var_set.count(2)是计算次数。set中的所有元素都是唯一的,所以count(key)的返回值只有0或1两种状态。

124. 二叉树中的最大路径和

难度困难1066

路径 被定义为一条从树中任意节点出发,沿父节点-子节点连接,达到任意节点的序列。同一个节点在一条路径序列中 至多出现一次 。该路径 至少包含一个 节点,且不一定经过根节点。

路径和 是路径中各节点值的总和。

给你一个二叉树的根节点 root ,返回其 最大路径和

示例 1:

img

输入:root = [1,2,3]
输出:6
解释:最优路径是 2 -> 1 -> 3 ,路径和为 2 + 1 + 3 = 6

示例 2:

img

输入:root = [-10,9,20,null,null,15,7]
输出:42
解释:最优路径是 15 -> 20 -> 7 ,路径和为 15 + 20 + 7 = 42

提示:

  • 树中节点数目范围是 [1, 3 * 104]
  • -1000 <= Node.val <= 1000
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    int maxPathSum(TreeNode* root) {
        int ret = -1001;
        helper(root,ret);
        return ret;
    }

    int helper(TreeNode *node,int& res)
    {
        if (!node)
            return 0;
        int left = max(helper(node->left,res),0); //孩子值可能为负数,所以和0做对比,避免无用的“负”担
        int right = max(helper(node->right,res),0);     

        res = max(res,left+right+node->val);//此节点为根节点时构成的路径和若是超过当前最大路劲和res,那么就替换res为当前最大路径和。
        return max(left,right) + node->val;//node不为根节点时,其必须和其左右孩子节点中的一个在同一个路径上,那么当然是值不为0且更大的那一个,但是两个孩子可能都为负数,此时就抛弃孩子不让其参与到路径中
    }
};

思路:

某个点,有可能以它为根节点,与其左右子树构成最大路径和,也有可能该节点只是最大路径和上的一个旁节点。如下的node A;

在这里插入图片描述

所以,我们在递归的过程中,要计算这两种情况,对于第一种情况,因为我们的回溯是从叶子节点向上的,所以当遍历到某个节点,我们不会再往下,那么我们就可以直接计算其为根节点时的路径和,并与当前最大路径和比较。

 res = max(res,left+right+node->val);

同时,我们是从下到上的,那万一上面有一个节点F为根节点,与当前在其分支上的节点A其构成题目要求的最大路径和呢?所以在从下到上的回溯过程中我们要返回这种情况时的最大值,即A非根节点时其只能和其左右子树C和B中的最大者构成路径;又或者由于C、B(为根)的都是部分路径和为负数,此时只将A单独参与到最大路径的构成上去。

543. 二叉树的直径

难度简单714收藏分享切换为英文接收动态反馈

给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过也可能不穿过根结点。

示例 :
给定二叉树

          1
         / \
        2   3
       / \     
      4   5    

返回 3, 它的长度是路径 [4,2,1,3] 或者 [5,2,1,3]。

**注意:**两结点之间的路径长度是以它们之间边的数目表示。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    int reculenth(TreeNode *pnode,int& ret)
    {
        if (!pnode || (!pnode->left && !pnode->right))
        {
            return 0;
        }
        
        int left = max(reculenth(pnode->left,ret),0);
        int right = max(reculenth(pnode->right,ret),0);

        if (pnode->left && pnode->right)
        {
            ret = max(ret,left + right + 2);//pnode此时作为根节点和其左右子树构成直径,所有左右子树的直径加上分别连接上pnode后新增的两个单位的路径
        }
        else 
        {
            ret = max(ret,left + right + 1);//pnode此时作为根节点和其左右子树构成直径,所有左右子树的直径加上分别连接上pnode后新增的两个单位的路径
        }

        return max(left,right) + 1;//pnode以非根节点的节点身份构成直径,那么其左右子树只能取其一作为直径的一部分,那么按照题意,当然取最长的
    }

    int diameterOfBinaryTree(TreeNode* root) {
        
        int ret = -0xfffffff;
        ret = max(reculenth(root,ret),ret);
        return ret;
    }
};

448. 找到所有数组中消失的数字

难度简单751收藏分享切换为英文接收动态反馈

给你一个含 n 个整数的数组 nums ,其中 nums[i] 在区间 [1, n] 内。请你找出所有在 [1, n] 范围内但没有出现在 nums 中的数字,并以数组的形式返回结果。

示例 1:

输入:nums = [4,3,2,7,8,2,3,1]
输出:[5,6]

示例 2:

输入:nums = [1,1]
输出:[2]

提示:

  • n == nums.length
  • 1 <= n <= 105
  • 1 <= nums[i] <= n

**进阶:**你能在不使用额外空间且时间复杂度为 O(n) 的情况下解决这个问题吗? 你可以假定返回的数组不算在额外空间内。

class Solution {
public:
    vector<int> findDisappearedNumbers(vector<int>& nums) {
        vector<int> ret;
        for (int i = 0; i < nums.size();++i)
        {
            nums[abs(nums[i]) -1] = - abs(nums[abs(nums[i]) -1]);
        }

        for (int i = 0; i < nums.size();++i)
        {
            if (nums[i] > 0)
            {
                ret.push_back(i+1);
            }
        }

        return ret;
    }
};

283. 移动零

难度简单1077收藏分享切换为英文接收动态反馈

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

示例:

输入: [0,1,0,3,12]
输出: [1,3,12,0,0]

说明:

  1. 必须在原数组上操作,不能拷贝额外的数组。
  2. 尽量减少操作次数。
class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        if (nums.size() <= 0)
        {
            return;
        }

       int l_p = 0;//左指针永远指向数组中第一个0
       int r_p = 0;//右指针永远指向左指针以后的第一个非0

        while (r_p < nums.size())
        {
            while (l_p < nums.size() && nums[l_p] != 0)
            {
                ++l_p;
            }

            r_p = l_p+1;

            while (r_p < nums.size() && nums[r_p] == 0)
            {
                ++r_p;
            }

            if (l_p >= nums.size() || r_p >= nums.size())
            {
                break;
            }

            nums[l_p] ^= nums[r_p];
            nums[r_p] ^= nums[l_p];
            nums[l_p] ^= nums[r_p];
        }

        return;
    }
};

思路:

双指针,左指针l_p永远指向数组中第一个为0的元素,右指针永远指向左指针以后的第一个非0元素,此时交换左右指针指向的元素,就能将首0元素和首非0元素交换。这样就能得到题目要求。

461. 汉明距离

难度简单486收藏分享切换为英文接收动态反馈

两个整数之间的 汉明距离 指的是这两个数字对应二进制位不同的位置的数目。

给你两个整数 xy,计算并返回它们之间的汉明距离。

示例 1:

输入:x = 1, y = 4
输出:2
解释:
1   (0 0 0 1)
4   (0 1 0 0)
       ↑   ↑
上面的箭头指出了对应二进制位不同的位置。

示例 2:

输入:x = 3, y = 1
输出:1

提示:

  • 0 <= x, y <= 231 - 1
class Solution {
public:
    int hammingDistance(int x, int y) {
        
        int num = x^y;
        int dist = 0;

        while (num != 0)
        {
            if (num&0x1 == 1)
            {
                ++dist;
            }

            num>>=1;
        }
        
        return dist;
    }
};

17. 电话号码的字母组合

难度中等1347收藏分享切换为英文接收动态反馈

给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。

给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。

img

示例 1:

输入:digits = "23"
输出:["ad","ae","af","bd","be","bf","cd","ce","cf"]

示例 2:

输入:digits = ""
输出:[]

示例 3:

输入:digits = "2"
输出:["a","b","c"]

提示:

  • 0 <= digits.length <= 4
  • digits[i] 是范围 ['2', '9'] 的一个数字。
class Solution {
public:
    map<char,string> mp = {{'2',"abc"},{'3',"def"},{'4',"ghi"},{'5',"jkl"},  {'6',"mno"},{'7',"pqrs"},{'8',"tuv"},{'9',"wxyz"}};
    vector<string> res;
    string cur;

    vector<string> letterCombinations(string digits) {
        if (digits.size() <= 0)
        {
            return res;
        }

        dfs(digits);
        return res;
    }

    void dfs(string digits)
    {
        if (!digits.size())
        {
            res.push_back(cur);
            return;
        }
        else 
        {
            string letter = mp[digits[0]];
            for (int i = 0;i < letter.size();++i)
            {
                cur.push_back(letter[i]);
                dfs(digits.substr(1));
                cur.pop_back();
            }
        }
    }
};

首先要明确题目要求的组合是什么形式的?

  1. 题目给出数字字符串digits,然后要求我们按照digits中每个字符对应的数字在键盘中对应的字符符来互相组合,组合出长度为strlen(digits)的字符串,这个字符串每个字母都唯一来自该数字所在的键位中的某个字符。

  2. 既然是组合问题,那么很大可能就是DFS,那如何得到呢?既然返回结果中的每一个string中的每一个字母都唯一来自不同键位,那么我们就当买菜,分别从各键位只挑一个来组合即可

82. 删除排序链表中的重复元素 II

难度中等634收藏分享切换为英文接收动态反馈

存在一个按升序排列的链表,给你这个链表的头节点 head ,请你删除链表中所有存在数字重复情况的节点,只保留原始链表中 没有重复出现 的数字。

返回同样按升序排列的结果链表。

示例 1:

img

输入:head = [1,2,3,3,4,4,5]
输出:[1,2,5]

示例 2:

img

输入:head = [1,1,1,2,3]
输出:[2,3]

提示:

  • 链表中节点数目在范围 [0, 300]

  • -100 <= Node.val <= 100

  • 题目数据保证链表已经按升序排列

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* deleteDuplicates(ListNode* head) {
        if (!head || !head->next)//确保至少有两个结点
        {
            return head;
        }
        
        ListNode *pnewhead = new ListNode(-1);
        ListNode *ptmp = pnewhead;
        pnewhead->next = head;
        ListNode *p1 = head;
        ListNode *p2 = head->next;

        while (p2)
        {
            if (p1->val == p2->val)
            {
                while (p1->val == p2->val)//找到结点同值的最右结点的下一个结点
                {
                    p2 = p2->next;
                    if (!p2)
                    {
                        pnewhead->next = NULL;
                        return ptmp->next;
                    }
                }

                p1 = p2;
                p2 = p2->next;
            }
            else 
            {
                pnewhead->next = p1;
                pnewhead = p1;

                p1 = p2;
                p2 = p2->next;
            }
        }

        pnewhead->next = p1;
        return ptmp->next;
    }
};

思路:

当p1和p2相等时,就循环找到p2往后的第一个和p1不等的结点,然后重复上述过程,直到找到一个唯一的结点,此时就将其加入题目要求的链表。

10. 正则表达式匹配

难度困难2173收藏分享切换为英文接收动态反馈

给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 '.''*' 的正则表达式匹配。

  • '.' 匹配任意单个字符
  • '*' 匹配零个或多个前面的那一个元素

所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。

示例 1:

输入:s = "aa" p = "a"
输出:false
解释:"a" 无法匹配 "aa" 整个字符串。

示例 2:

输入:s = "aa" p = "a*"
输出:true
解释:因为 '*' 代表可以匹配零个或多个前面的那一个元素, 在这里前面的元素就是 'a'。因此,字符串 "aa" 可被视为 'a' 重复了一次。

示例 3:

输入:s = "ab" p = ".*"
输出:true
解释:".*" 表示可匹配零个或多个('*')任意字符('.')。

示例 4:

输入:s = "aab" p = "c*a*b"
输出:true
解释:因为 '*' 表示零个或多个,这里 'c' 为 0 个, 'a' 被重复一次。因此可以匹配字符串 "aab"。

示例 5:

输入:s = "mississippi" p = "mis*is*p*."
输出:false

提示:

  • 0 <= s.length <= 20

  • 0 <= p.length <= 30

  • s 可能为空,且只包含从 a-z 的小写字母。

  • p 可能为空,且只包含从 a-z 的小写字母,以及字符 .*

  • 保证每次出现字符 * 时,前面都匹配到有效的字符

class Solution {
public:
    bool isMatch(string s, string p) {
        
        if (p.empty()) return s.empty();

        if (p.size() == 1) {
            return (s.size() == 1 && (s[0] == p[0] || p[0] == '.'));
        }

        if (p[1] != '*') {//说明p至少需要去匹配s中的一个字符
            if (s.empty()) return false;//若此时s为空,那一定不满足条件
            return (s[0] == p[0] || p[0] == '.') && isMatch(s.substr(1), p.substr(1));
        }

        while (!s.empty() && (s[0] == p[0] || p[0] == '.')) 
        {
            if (isMatch(s, p.substr(2))) //这样做的原因是假设此时的星号的作用是让前面的字符出现0次,验证是否匹配(即,从p当前的*的下一个字符去匹配s)
            {
                return true;
            }

            s = s.substr(1);//若上面假设的s[i]出现0次匹配失败了,那么我们就从s的下一个字符开始匹配,而p为什么不动呢?因为p可匹配的字母是0或多个,这里的else逻辑是这多个的分支,而多个决定我们不用移动p

        }

        return isMatch(s, p.substr(2));//若上面的情况都没有结果,那么就要在p之后的两个字符以后开始匹配
    }
};

标签:head,return,nums,int,ret,tail,c++,leetcode
来源: https://blog.csdn.net/dengwodaer/article/details/117842695

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有