算法题合集

Sheldon的刷题笔记

字符串处理

1694. 重新格式化电话号码

  • 字符串模拟
class Solution {
public:
    string reformatNumber(string number) {
        string ans = "";
        for(int i = 0,num = 0; i < number.size(); i++)
        {
            if(!isdigit(number[i])) continue;
            ans += number[i];
            num ++;
            if(num == 3)
            {
                num = 0;
                ans += '-';
            }
        }
        int n = ans.size();
        if(ans[n - 1] == '-') ans.pop_back();//可以被3整除的情况
        if(n > 2 && ans[n - 2] == '-') swap(ans[n - 2],ans[n - 3]);//剩下4个
        return ans;

    }
};

38. 外观数列

class Solution {
public:
    string countAndSay(int n) {
        string s = "1";
        for(int i = 0; i < n - 1; i++)
        {
            string ns = "";//每一次循环的当前值
            for(int left = 0; left < s.size();)
            {
                int right = left;//找到终点
                while(right < s.size() && s[right] == s[left]) right++;
                ns += to_string(right - left);//该字符个数
                ns += s[left];//该字符
                left = right;
            }
            s = ns;
        }
        return s;
    }
};

49. 字母异位词分组

  • 哈希+排序
class Solution {
public:
    vector<vector<string>> groupAnagrams(vector<string>& strs) {
        unordered_map<string,vector<string>> hash;
        for(auto str:strs)
        {
            string key = str;
            sort(key.begin(),key.end());
            hash[key].push_back(str);
        }
        vector<vector<string>> res;
        for(auto item:hash) res.push_back(item.second);
        return res;
    }
};

DFS

200. 岛屿数量
思路:

  • 这是一道深搜的题
  • 如果我们碰到1,那么岛屿数量++。同时把与该"1"与及其相连的地方都变成0

CPP代码

class Solution {
public:

    void dfs(vector<vector<char>>& grid,int r,int c)
    {
        int nr = grid.size();
        int nc = grid[0].size();
        
        //把当前位置改为0
        grid[r][c] = '0';

        //其实这里是省略了边界的情况,边界默认为是什么都不干,因为边界一定会被旁边的给影响
        //把它四个方向为'1'的岛屿全部变成'0'
        //这里我们一定要保证我们的数据是合法的范围
        if(r-1 >= 0 && grid[r-1][c] == '1') dfs(grid,r-1,c);
        if(r+1 < nr && grid[r+1][c] == '1') dfs(grid,r+1,c);
        if(c-1 >= 0 && grid[r][c-1] == '1') dfs(grid,r,c-1);
        if(c+1 < nc && grid[r][c+1] == '1') dfs(grid,r,c+1);
        return;
    }




    int numIslands(vector<vector<char>>& grid) {
        int nr = grid.size();//行数
        if(!nr) return 0;//特判
        int nc = grid[0].size();//列数
        
        int num_islands=0;
        //依次遍历所有的行和列
        for(int r=0;r<nr;r++)
        {
            for(int c= 0;c<nc;c++)
            {
                if(grid[r][c]=='1') //碰到1我们就要把岛屿数量++
                {
                    num_islands++;
                    dfs(grid,r,c);
                }   
            }
        }
        return num_islands;
    }
};

BFS

279. 完全平方数

  • 本题我们可以把他理解成一个图论
  • 我们的每一个结点就是每一个数值
  • 加了平方项以后就从当前值转移到了另一个值
  • BFS常见套路
    • 定义一个队列,队列中有元素就一直循环
    • 初始时刻我们把起始点放入队列中,同时距离设置为0
    • 每次循环取出队头,弹出队头
    • 对我们取出来的队头做一定的处理
    • 得到新的结果,存到队列中
class Solution {
public:
    int numSquares(int n) {
        queue<int> q;
        vector<int> dist(n + 1,INT_MAX);//定义距离,所有点到起点的距离
        q.push(0);
        dist[0] = 0;//起点是0
        while(q.size()){
            int t = q.front();//当前点
            q.pop();
            if(t == n) return dist[t];//走到了终点
            //否则我们枚举当前点t可以走到哪些点
            for(int i = 1; i * i + t <= n; i++){
                int j = t + i * i;
                if(dist[j] > dist[t] + 1){//说明我们的j可以从t过来
                    dist[j] = dist[t] + 1;//更新我们的j值
                    q.push(j);
                }
            }       
        }
        return 0;
    }
};

双指针

167. 两数之和 II - 输入有序数组

class Solution {
public:
    vector<int> twoSum(vector<int>& numbers, int target) {
        int i = 0, j = numbers.size() - 1;
        while(i < j){
            while(numbers[i] + numbers[j] > target && i < j) j--;
            while(numbers[i] + numbers[j] < target && i < j) i++;
            if(numbers[i] + numbers[j] == target) return {i + 1,j + 1};
        }
        return {-1,-1};
    }
};

88. 合并两个有序数组

class Solution {
public:
    void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
        int p1 = m - 1, p2 = n - 1,p3 = nums1.size() - 1;
        
        while(p1 >= 0 && p2 >= 0){
            if(nums1[p1] > nums2[p2]) nums1[p3--] = nums1[p1--];
            else nums1[p3--] = nums2[p2--];
        }
        //结束条件是p1或者p2中有一个不符合条件
        while(p2>=0) nums1[p3--] = nums2[p2--];
    }
};

单调队列

滑动窗口

动态规划

64. 最小路径和

  • 本题是一个比较简单的动态规划问题
class Solution {
public:
    int minPathSum(vector<vector<int>>& grid) {
        int m = grid.size(), n = grid[0].size();
        if(m == 0 || n == 0) return 0;//特判
        vector<vector<int>> f(m,vector<int>(n));//定义我们的答案
        f[0][0] = grid[0][0];
        //下面2行是处理一下边界条件
        for(int i = 1; i < n; i++) f[0][i] = grid[0][i] + f[0][i - 1];
        for(int i = 1; i < m; i++) f[i][0] = grid[i][0] + f[i - 1][0];
        for(int i = 1; i < m; i++){
            for(int j = 1; j < n; j++)
                f[i][j] = min(f[i - 1][j],f[i][j - 1]) + grid[i][j];
        }
        return f[m - 1][n - 1];
    }
};

62. 不同路径

  • 这题跟64题,差不多
  • 直接递推就可以了
  • 记住要处理一下边界情况!
class Solution {
public:
    int uniquePaths(int m, int n) {
        vector<vector<int>> f(m,vector<int>(n));
        f[0][0] = 1;
        for(int i = 0; i < m; i++)
            for(int j = 0; j < n; j++)
                if(i == 0 || j == 0) f[i][j] = 1;
                else f[i][j] = f[i - 1][j] + f[i][j - 1];
        return f[m - 1][n - 1];
    }
};

120. 三角形最小路径和

  • 这是一道经典的动态规划入门题
  • 思路
    • 从下到上枚举,这样的话我们的答案就存在g[0]中,如果我们从上到下枚举的话,我们得额外处理边界情况
    • 动态转移方程:g[i]=min(g[i],g[i + 1]) + triangle[i][j]
class Solution {
public:
    int minimumTotal(vector<vector<int>>& triangle) {
        int n = triangle.size();
        vector<int> g(n);
        //处理一下最后一层
        for(int i = 0; i < n; i++) g[i] = triangle[n - 1][i];
        for(int i = n - 2; i >= 0; i--){
            for(int j = 0; j <= i; j++)
                g[j] = min(g[j],g[j + 1]) + triangle[i][j];
        }
        return g[0];
    }
};

63. 不同路径 II

  • 对于有障碍的地方直接跳过
  • 初始的时候vector为0,所以对于有障碍的地方它要加也是加0
class Solution {
public:
    int uniquePathsWithObstacles(vector<vector<int>>& g) {
        int n = g.size(), m = g[0].size();
        vector<vector<long long>> f(n,vector<long long>(m));//定义我们的状态矩阵
        for(int i = 0; i < n; i++){
            for(int j = 0; j < m; j++){
                if(g[i][j]) continue;//如果该点是障碍我们什么都不做
                if(!i && !j) f[i][j] = 1;//起点设为1
                if(i) f[i][j] += f[i - 1][j];//从上面过来的
                if(j) f[i][j] += f[i][j - 1];//从左边过来的
            }
        }
        return f[n - 1][m - 1];
    }
};

贪心

55. 跳跃游戏

  • 这题不会做
  • 看完官方的题解,只能说太妙了...
  • 我们只需遍历每一个位置(注:最有小于m的地方我们才可以遍历到),判断最远可以到达的位置是否大于等于n-1即可
class Solution {
public:
    bool canJump(vector<int>& nums) {
        int n = nums.size();
        int m = 0;//可到达的最远的地方
        for(int i = 0; i < n; i++){
            if(i <= m){//只有小于m的地方我们才有机会遍历到
                m = max(m,i + nums[i]);
                if(m >= n - 1)
                    return true;
            }
        }
        return false;
    }
};
posted @ 2022-09-29 19:04  Sheldon2  阅读(17)  评论(0编辑  收藏  举报