leetcode-hot100

文章目录

哈希

两数之和

题目

题目链接

代码

cpp 复制代码
class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        // 方法1:暴力搜索
        for(int i = 0; i < nums.size() - 1; i++)
        {
            for(int j = i + 1; j < nums.size(); j++)
            {
                if(nums[i] + nums[j] == target)
                {
                    return {i, j};
                }
            }
        }
        return {};
    }
};
cpp 复制代码
// 方法二:哈希表
class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
      unordered_map<int, int> hash;
      for(int i = 0; i < nums.size(); i++)
      {
        int t = target - nums[i];
        if(hash.count(t)) return {hash[t], i};
        hash[nums[i]] = i;
      }
      return {};
    }
};

字母异位词分组

题目

题目链接

代码

cpp 复制代码
class Solution {
public:
    vector<vector<string>> groupAnagrams(vector<string>& strs) {
        unordered_map<string, vector<string>> hash;

        // 1. 把所有的字母异位词分组
        for(auto s : strs)
        {
            string tmp = s;
            sort(tmp.begin(), tmp.end());
            hash[tmp].push_back(s);
        }

        // 2. 把结果提取出来
        vector<vector<string>> ret;
        for(auto& [x, y] : hash)
        {
            ret.push_back(y);
        }
        return ret;
    }
};

最长连续序列

题目

题目链接

代码

cpp 复制代码
// 这个代码是我自己写的,逻辑跟下面的代码是一样的
class Solution {
public:
    int longestConsecutive(vector<int>& nums) {
        unordered_set<int> st(nums.begin(), nums.end());
        int ret = 0;

        for(auto& x : st)
        {
            if(st.count(x - 1)) continue;
            int y = x + 1;
            while(st.count(y))
            {  
                y++;
            }
            ret = max(y - x, ret);
        }
        return ret;
    }
};
cpp 复制代码
class Solution {
public:
    int longestConsecutive(vector<int>& nums) {
        int ans = 0;
        unordered_set<int> st(nums.begin(), nums.end());
        for(int x : st)
        {
            if(st.contains(x - 1))
                continue;
            int y = x + 1;
            while(st.contains(y))
                y++;
            ans = ranges::max(ans, y - x);
        }
        return ans;
    }
};

双指针

移动零

题目

题目链接

代码

cpp 复制代码
class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        int cur = 0, dest = -1;
       while(cur < nums.size())
        {
            if(nums[cur])
                swap(nums[cur++], nums[++dest]);
            else
                  cur++;
        }
    }
};

盛最多水的容器

题目

题目链接

代码

cpp 复制代码
// 我第二遍自己写出来的代码,方法跟下面的代码是一样的
class Solution {
public:
    int maxArea(vector<int>& height) {
        int n = height.size(), ans = 0;
        int left = 0, right = n - 1;
        while(left < right)
        {
            int h = min(height[left], height[right]);
            ans = max(ans, (right - left) * h);
            height[left] < height[right] ? left++ : right--;
        }
        return ans;
    }
};
cpp 复制代码
class Solution {
public:
    int maxArea(vector<int>& height) {
        int n = height.size(), ans = 0;
        int left = 0, right = n - 1;
        while(left < right)
        {
            int a = min(height[left], height[right]);
            ans = max(ans, a * (right - left));
            if(height[left] < height[right])
                left++;
            else
                right--;
        }
        return ans;
    }
};

三数之和

题目

代码

cpp 复制代码
class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
       sort(nums.begin(), nums.end());
       vector<vector<int>> ans;
       int n = nums.size();
       for(int i = 0; i < n - 2; i++)
       {
            int j = i + 1, k = n - 1;
            // 在解决"三数之和"问题时,为了避免重复的三元组,需要跳过重复的起始数字。
            //例如,对于数组 [1, 1, 2, -3, 0],如果第一个数字 1 已经被用作起始数字进行过遍历,
            //那么第二个 1 再次作为起始数字时,会产生重复的三元组。
            if(i && nums[i] == nums[i - 1]) continue;
            if(nums[i] + nums[i + 1] + nums[i + 2] > 0) break;
            if(nums[i] + nums[n - 2] + nums[n - 1] < 0) continue;
            while(j < k)
            {
                int s = nums[i] + nums[j] + nums[k];
                if(s < 0) j++;
                else if(s > 0) k--;
                else
                {
                    ans.push_back({nums[i], nums[j], nums[k]});
                    for(j++; j < k && nums[j] == nums[j - 1]; j++);
                    for(k--; j < k && nums[k] == nums[k + 1]; k--);
                } 
            }
       }
       return ans;
    }
};

接雨水

题目

代码

cpp 复制代码
// 法一:前后缀分解
class Solution {
public:
    int trap(vector<int>& height) {
        int n = height.size(), ans = 0;
        // pre_max[i] 表示从 height[0] 到 height[i] 的最大值
        // suf_max[i] 表示从 height[i] 到 height[n-1] 的最大值
        vector<int> pre_max(n), suf_max(n);
        pre_max[0] = height[0];
        suf_max[n - 1] = height[n - 1];
        for(int i = 1; i < n; i++)
            pre_max[i] = max(pre_max[i - 1], height[i]);
        for(int j = n - 2; j >= 0; j--)
            suf_max[j] = max(suf_max[j + 1], height[j]);
        // 累加每个水桶能接多少水
        for(int i = 0; i < n; i++)
            ans += min(pre_max[i], suf_max[i]) - height[i];
        
        return ans;
    }
};
// 时间复杂度:O(n),其中 n 为 height 的长度。
// 空间复杂度:O(n)。
cpp 复制代码
// 法二:相向双指针
class Solution {
public:
    int trap(vector<int>& height) {
        int ans = 0, left = 0, right = height.size() - 1, pre_max = 0, suf_max = 0;
        while (left < right) {
            pre_max = max(pre_max, height[left]);
            suf_max = max(suf_max, height[right]);
            ans += pre_max < suf_max ? pre_max - height[left++] : suf_max - height[right--];
        }
        return ans;
    }
};
cpp 复制代码
// 法三:单调栈方法
class Solution {
public:
    int trap(vector<int>& height) {
        stack<int> st;
        int n = height.size();
        int ans = 0;
        for(int i = 0; i < n; i++)
        {
            while(!st.empty() && height[i] >= height[st.top()])
            {
            	// 底部的高度
                int bottom_h = height[st.top()];
                st.pop();
                if(st.empty())
                {
                    break;
                }
                // 左边界
                int left = st.top();
                // 高度 = (左右边界的最小值) - 底部的高度
                int h = min(height[left], height[i]) - bottom_h; // 面积的高
                // 面积
                ans += h * (i - left - 1);
            }
            // 入栈
             st.push(i);
        }
        return ans;
    }
};
// 时间复杂度O(n)
// 空间复杂度O(min(n,U))   U=max(height)−min(height)+1

滑动窗口

无重复字符的最长子串

题目

代码

cpp 复制代码
class Solution {
public:
    int lengthOfLongestSubstring(string s) {
       unordered_map<char, int> ci;
       int ret = 0;
       for(int left = 0, right = 0; right < s.size(); right++)
       {
            ci[s[right]]++;
            while(ci[s[right]] > 1)
                ci[s[left++]]--;
            ret = max(ret, right - left + 1);
       }
       return ret;
    }
};

找到字符串中所有字母异位词

题目

代码

cpp 复制代码
class Solution {
public:
    vector<int> findAnagrams(string s, string p) {
        int m = p.size(), n = s.size(), hash1[26] = {0}, hash2[26] = {0};
        vector<int> ret;
        for(auto c : p) hash2[c - 'a']++;
        for(int left = 0, right = 0, count = 0; right < n; right++)
        {
            hash1[s[right] - 'a']++;
            if(hash1[s[right] - 'a'] <= hash2[s[right] - 'a']) count++;
            if(right - left + 1 > m)
            {
                if(hash1[s[left] - 'a'] <= hash2[s[left] - 'a']) count--;
                hash1[s[left] - 'a']--;
                left++;
            }
            if(count == m) ret.push_back(left);
        }
        return ret;
    }
};

回溯

电话号码的字母组合

题目

题目链接

思路


代码

bash 复制代码
class Solution {
    vector<string> ret;
    string hash[10] = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
    string path;
public:
    vector<string> letterCombinations(string digits) {
        // 判断边界(特殊情况)
        if(digits.size() == 0) return ret;

        dfs(digits, 0);
        return ret;
    }

    void dfs(string digits, int pos)
    {
        //递归出口
        if(pos == digits.size())
        {
            ret.push_back(path);
            return;
        }

        //遍历pos对应的hash中的位置
        for(auto ch : hash[digits[pos] - '0'])
        {
            path.push_back(ch);//先把这个字符加入到path
            dfs(digits, pos + 1);//递归:深度优先遍历
            path.pop_back();// 恢复现场,回溯到初始,去另一个分支继续迭代
        }
    }
};

括号生成

题目

题目链接

思路


代码

cpp 复制代码
class Solution {
    int left, right, n; // left记录左括号数量,right记录右括号数量,n记录总的括号对数
    string path; // path记录每次递归的字符串
    vector<string> ret; // ret保存最终的return结果

public:
    vector<string> generateParenthesis(int _n) {
        // 把传入的_n的值赋值给全局变量n
        n = _n;
        dfs();

        return ret;
    }

    void dfs()
    {
        // 递归出口
        if(right == n)
        {
            ret.push_back(path);
            return;
        }

        // 判断是否可以加左括号
        if(left < n)
        {
            path.push_back('('); left++;
            dfs();
            path.pop_back(); left--; // 恢复现场
        }

        // 判断是否可以加右括号
        if(right < left)
        {
            path.push_back(')'); right++;
            dfs();
            path.pop_back(); right--; // 恢复现场
        }
    }
};

组合总和

题目

题目链接

思路



代码

cpp 复制代码
// 解法一:按位置来,每个位置 每个nums[i]都试一下
class Solution {
    // 把整型参数不写成全局变量,而是写到dfs的参数,可以避免回溯;
    int aim; // 存储目标值的 全局变量
    vector<int> path; // 存储单次递归的结果
    vector<vector<int>> ret; // 存储最终return的结果
public:
    vector<vector<int>> combinationSum(vector<int>& nums, int target) {
        aim = target;
        dfs(nums, 0, 0);
        return ret;
    }

    // pos为nums中元素的位置,从第一个位置开始,直到最后一个位置
    // sum为当前递归路径的和
    void dfs(vector<int>& nums, int pos, int sum)
    {
        // 递归终止条件一,完成题目要求的条件
        if(sum == aim)
        {
            ret.push_back(path);
            return;
        }

        // 递归终止条件二,超范围或不满足题意
        if(sum > aim || pos > nums.size()) return;

        // 循环遍历
        for(int i = pos; i < nums.size(); i++)
        {
            path.push_back(nums[i]);
            dfs(nums, i, sum + nums[i]); // 第二个参数是i,不是i加一,因为元素可以重复;
            // 第二个元素是sum + nums[i],因为这里没有改变sum的值,所以sum不用恢复现场
            path.pop_back();
        }
    }
};
cpp 复制代码
// 方法二:先选nums[0],再选nums[1], 再选nums[2], 再选......
class Solution {
    // 把整型参数不写成全局变量,而是写到dfs的参数,可以避免回溯;
    int aim; // 存储目标值的 全局变量
    vector<int> path; // 存储单次递归的结果
    vector<vector<int>> ret; // 存储最终return的结果
public:
    vector<vector<int>> combinationSum(vector<int>& nums, int target) {
        aim = target;
        dfs(nums, 0, 0);
        return ret;
    }

    // pos为nums中元素的位置,从第一个位置开始,直到最后一个位置
    // sum为当前递归路径的和
    void dfs(vector<int>& nums, int pos, int sum)
    {
        // 递归终止条件一,完成题目要求的条件
        if(sum == aim)
        {
            ret.push_back(path);
            return;
        }

        // 递归终止条件二,超范围或不满足题意
        if(sum > aim || pos == nums.size()) return;

        // 枚举个数
        for(int k = 0; k * nums[pos] <= aim; k++)
        {
            // 当个数不是0的时候,才加入到path中
            if(k) path.push_back(nums[pos]);
            dfs(nums, pos + 1, sum + k * nums[pos]); 
        }

        //恢复现场
        //这里必须,在循环外恢复现场,把加到path的i个nums[pos]全pop掉
        for(int i = 1; i * nums[pos] <= aim; i++)
        {
            path.pop_back();
        }
    }
};

N皇后

题目

题目链接

思路

代码

cpp 复制代码
class Solution {
    bool checkCol[10], checkDig1[20], checkDig2[20];
    vector<string> path;
    vector<vector<string>> ret;
    int n;

public:
    vector<vector<string>> solveNQueens(int _n) {
        n = _n;
        path.resize(n);
        for(int i = 0; i < n; i++)
        {
            //是向 path[i] 中追加 n 个 '.' 字符
            //string& append(size_t count, char ch);
            path[i].append(n, '.');
        }

        dfs(0);
        return ret;
    }

    void dfs(int row)
    {
        if(row == n)
        {
            ret.push_back(path);
            return;
        }

        //遍历本行的每一列
        for(int col = 0; col < n; col++)
        {
            if(!checkCol[col] && !checkDig1[row - col + n] && !checkDig2[row + col])
            {
                path[row][col] = 'Q';
                checkCol[col] = checkDig1[row - col + n] = checkDig2[row + col] = true;
                // 下一行递归
                dfs(row + 1);
                // 恢复现场
                path[row][col] = '.';
                checkCol[col] = checkDig1[row - col + n] = checkDig2[row + col] = false;
            }
        }
    }
};

单词搜索

题目

题目链接

思路



代码

相关推荐
eyexin20181 小时前
大模型量化与剪枝
算法·机器学习·剪枝
普通网友1 小时前
C# 中委托和事件的深度剖析与应用场景
java·算法·c#
安全系统学习2 小时前
网络安全之任意文件读取利用
算法·安全·web安全·网络安全·哈希算法
电院工程师2 小时前
2.4 Python基础概念:通过一个文字冒险游戏学习编程
开发语言·python·学习·算法·游戏·游戏程序
没故事的燕同学2 小时前
[GESP202306 三级] 密码合规
算法
钢铁男儿3 小时前
C#数组完全指南:从基础到多维数组解析
数据结构·算法
黑听人3 小时前
【力扣 C】力扣刷题目录
c语言·leetcode
豆沙沙包?3 小时前
2025年- H82-Lc190--322.零钱兑换(动态规划)--Java版
java·算法·动态规划
Coovally AI模型快速验证3 小时前
数据集分享 | 电力检测数据集,助力AI守护电网安全
人工智能·算法·安全·计算机视觉·目标跟踪
IT古董4 小时前
【第二章:机器学习与神经网络概述】01.聚类算法理论与实践-(1)K-means聚类算法
人工智能·算法·聚类