C/C++教程

c++刷leetcode

本文主要是介绍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之后的两个字符以后开始匹配
    }
};

这篇关于c++刷leetcode的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!