Leetcode错题记录

本文深入探讨了多种算法问题的解决方案,包括寻找三数之和、四数之和、最接近的三数之和,以及电话号码的组合、括号生成等。此外,还详细介绍了如何使用动态规划、回溯搜索、贪心策略解决组合求和、跳跃游戏、全排列、接雨水、跳跃游戏II、最大子序和等问题。文章还涵盖了合并升序链表、N皇后问题以及不同的路径计算。通过对这些问题的分析,展示了在信息技术领域中如何应用高效算法解决复杂问题。
摘要由CSDN通过智能技术生成

15三数之和

在这里插入图片描述
在这里插入图片描述

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        vector<vector<int>> res;
        for(int i=0;i<nums.size();i++){
            if(i>0 && nums[i]==nums[i-1]) continue; //重复的元素不需要再来一遍
            for(int j=i+1,k=nums.size()-1;j<k;j++){
                if(j>i+1 &&nums[j]==nums[j-1]) continue; //同样重复的元素不需要再枚举
                while(j < k-1 && nums[i]+nums[j]+nums[k]>0) k--;
                if(nums[i]+nums[j]+nums[k]==0) res.push_back({nums[i],nums[j],nums[k]});
            }
        }
        return res;

    }
};
class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        vector<vector<int>> res;
        for(int i=0;i<nums.size();i++){
            if(i>0 && nums[i]==nums[i-1]) continue;
            for(int j=i+1,k=nums.size()-1;j<k;j++){
                if(j>i+1 && nums[j]==nums[j-1]) continue;
                while(k-1 > j && nums[i]+nums[j]+nums[k-1]>=0) k--;
                if(nums[i]+nums[j]+nums[k]==0){
                    res.push_back({nums[i],nums[j],nums[k]});
                }
            }
        }
        return res;

    }
};

18四数之和

在这里插入图片描述

class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        sort(nums.begin(), nums.end());
        vector<vector<int>> res;
        for (int i = 0; i < nums.size(); i ++ ) {
            if (i && nums[i] == nums[i - 1]) continue;
            for (int j = i + 1; j < nums.size(); j ++ ) {
                if (j > i + 1 && nums[j] == nums[j - 1]) continue;
                for (int k = j + 1, u = nums.size() - 1; k < u; k ++ ) {
                    if (k > j + 1 && nums[k] == nums[k - 1]) continue;
                    while (u - 1 > k && nums[i] + nums[j] - target >= -nums[k] - nums[u - 1]) u -- ;
                    //这里是nums[i]+nums[j]+nums[k]+nums[u-1]>=target为了防止溢出,给方程做了变形
                    if (nums[i]+nums[j]-target==-nums[k]-nums[u]) {
                        //这里是nums[i]+nums[j]+nums[k]+nums[u-1]==target为了防止溢出,给方程做了变形
                        res.push_back({nums[i], nums[j], nums[k], nums[u]});
                    }
                }
            }
        }

        return res;
    }
};


16最接近的三数之和

在这里插入图片描述
在这里插入图片描述

class Solution {
public:
    int threeSumClosest(vector<int>& nums, int target) {
        sort(nums.begin(),nums.end());
        pair<int,int>res(INT_MAX,INT_MAX);  //第一个存储的是target-s的差值,第二个是s
        for(int i=0;i<nums.size();i++)
        {
            for(int j=i+1,k=nums.size()-1;j<k;j++)
            {
                while(j<k-1&&nums[i]+nums[j]+nums[k-1]>target) k--; //要找到满足最小的k
                int s=nums[i]+nums[j]+nums[k];
                //之所以s-target<0 是因为while的判断里有两个条件,循环退出时有可能是第一个条件不满足。
                res=min(res,make_pair(abs(s-target),s));
                if (k - 1 > j) 
                {
                    s = nums[i] + nums[j] + nums[k - 1];
                    res = min(res, make_pair(target - s, s));
                }
            }
        }
        return res.second;
    }
};


17电话号码的组合(dfs)

在这里插入图片描述

class Solution {
public:
    string strs[10] = {"","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
    vector<string> res;
    void dfs(string& digits,int level,string path){
        if(level==digits.size()){
            res.push_back(path);
            return;
        }
        int now_num = digits[level] - '0';
        for(int i=0;i<strs[now_num].size();i++){
            dfs(digits,level+1,path+strs[now_num][i]);
        }
    }

    vector<string> letterCombinations(string digits) {
        if(digits.empty()) return res;
        dfs(digits,0,"");
        return res;
    }
};

18括号生成

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

class Solution {
public:
    vector<string> res;
    void dfs(string seq,int left_num,int right_num,int n){
        //left_num是当前已经有的左括号数量,right_num是当前已经有的右括号的数量
        //seq是当前已经序列
        if(left_num==n && right_num==n){
            res.push_back(seq);
            return;
        }
        //因为我们只有在左括号数量大于右括号的时候才会放置右括号
        if(left_num<n) dfs(seq+'(',left_num+1,right_num,n);
        if(right_num<n && right_num < left_num) dfs(seq+')',left_num,right_num+1,n);


    }

    vector<string> generateParenthesis(int n) {
        dfs("",0,0,n);
        return res;

    }
};

23合并k个升序链表

在这里插入图片描述

/**
 * 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) {}
 * };
 */

//优先级队列的用法:
//priority_queue<Type, Container, Functional>
//对于基础类型 默认是大顶堆
//priority_queue<int> a; 
//等同于 priority_queue<int, vector<int>, less<int> > a; 
//priority_queue<int, vector<int>, greater<int> > c;  //这样就是小顶堆

struct cmp{
    bool operator () (ListNode* a,ListNode* b){
        return a->val > b->val;//这么写是小根堆
    }
};

class Solution {
public:
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        priority_queue<ListNode*,vector<ListNode*>,cmp> heap;
        ListNode* dummy = new ListNode(-1); //创建虚拟头节点
        ListNode* now_node = dummy;
        for(auto node:lists){
            if(node!=NULL) heap.push(node);//先把每个链的第一个节点放进去
        }
        while(!heap.empty())
        {
            ListNode* t = heap.top();
            now_node->next = t;
            now_node = now_node->next;
            if(t->next != NULL) heap.push(t->next);
            heap.pop();
        }
        return dummy->next;
    }
};

39组合求和(dfs)

不会有重复的元素,每个元素可以选择无限次

在这里插入图片描述

class Solution {
public:
    vector<vector<int>> res;
    vector<int> path;
    
    void dfs(vector<int>& candidates,int target,int u)//u表示当前搜索到第几个点了
    {
        
        //每次搜到一个值就从target里面减去
        if(target==0){//target减到0的时候表示是一个合法方案
            res.push_back(path);
            return;
        }
        if(u==candidates.size()) return;
        //搜索完所有节点但是都没有满足target==0

        //每个数可以取用多次,i表示这个数被取用几次
        for(int i=0;candidates[u]*i<=target;i++)
        {
            if(i!=0) path.push_back(candidates[u]);
            dfs(candidates,target-candidates[u]*i,u+1);
        }
        
        //恢复现场
        for(int i=0;candidates[u]*i<=target;i++)
        {
            if(i!=0) path.pop_back();
        }

    }

    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
        dfs(candidates,target,0);
        return res;
    }
};

40组合总和II

包含了重复的元素,每个元素只能够被选择1次

在这里插入图片描述

class Solution {
public:
    vector<vector<int>> res;
    vector<int> path;
    //这题与上一题的区别就是这题每个数只能用一次,但是这个数在这个数组里可能出现多次
    //所以可以把元素出现的次数求出来,就转化为上一个题了
    vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
        sort(candidates.begin(),candidates.end());
        dfs(candidates,0,target);
        return res;
    }
    //u这里仅仅是每个元素在candidates中第一次出现的位置
    void dfs(vector<int>& candidates,int u,int target)
    {
        if(target==0){
            res.push_back(path);
            return;
        }
        if(u==candidates.size()) return;

        int k = u+1;
        while(k < candidates.size() && candidates[k]==candidates[k-1]) k++;
        int cnt = k - u; //cnt即为这个元素在数组中出现的次数

        for(int i=0;i*candidates[u]<=target && i<=cnt; i++){
            if(i!=0) path.push_back(candidates[u]);
            dfs(candidates,u+cnt,target-candidates[u]*i);
        }
        for(int i=0;i*candidates[u]<=target && i<=cnt; i++){
            if(i>0) path.pop_back();
        }

    }
};

42接雨水(dp优化)

在这里插入图片描述
每个柱子计算其这个柱子的上方能够存储的水量,这个柱子上方能够存储的水量是由这个柱子左侧最高柱子和右侧最高柱子中的最小值决定的,最后答案只需要把所有柱子上方的存水量加起来就是最终答案。

暴力求i号柱子左右两边最大柱高O(n^2)
class Solution {
public:
    int trap(vector<int>& height) {
        int n = height.size();
        if(n==0) return 0;
        //求i号柱子左侧最高的柱子高度 和 右侧最高的柱子高度
        map<int,int> left_max,right_max;
        left_max[0] = 0;
        right_max[n-1] = 0;
        for(int i=1;i<height.size();i++)
        {
            int res = -1;
            for(int j=0;j<i;j++){
                res = max(res,height[j]);
            }
            left_max[i] = res;
        }

        for(int i=n-2;i>=0;i--){
            int res = -1;
            for(int j=i+1;j<n;j++){
                res = max(res,height[j]);
            }
            right_max[i] = res;

        }
        //我们看每一个柱子能够积水的数量,就是看i号柱子这一列上面最多能够积攒多少水
        //最后每一列上面能够积攒的水的数目加起来就是答案
        int res = 0;
        for(int i=0;i<n;i++){
            res+=max(0,min(left_max[i],right_max[i])-height[i]);//只有左右最小柱高度大于当前柱高height[i]时,才能积水
        }
        
        return res;
    }
};
优化求左右两端最高柱子
class Solution {
public:
    int trap(vector<int>& height) {
        int n = height.size();
        if(n==0) return 0;
        //求i号柱子左侧最高的柱子高度 和 右侧最高的柱子高度
        //用动态规划优化一下,求i号柱子左右两部分最高柱子高度
        vector<int> left_max(n),right_max(n);
        //left_num[i]表示i号柱子左侧的最高柱子高度
        left_max[0] = 0;
        right_max[n-1] = 0;
        for(int i = 1;i<n;i++) left_max[i] = max(left_max[i-1],height[i-1]);
        for(int i = n-2;i>=0;i--) right_max[i] = max(right_max[i+1],height[i+1]);
        
        //我们看每一个柱子能够积水的数量,就是看i号柱子这一列上面最多能够积攒多少水
        //最后每一列上面能够积攒的水的数目加起来就是答案
        int res = 0;
        for(int i=0;i<n;i++){
            res+=max(0,min(left_max[i],right_max[i])-height[i]);//只有左右最小柱高度大于当前柱高height[i]时,才能积水
        }
        
        return res;
    }
};

45跳跃游戏II(dp)

在这里插入图片描述
f[i] 表示从0号点到i号点能够跳跃的方案集合
属性 min, 跳跃次数最小值
显然f[0] = 0 ,f[1] = 1
并且一定有 f[i] <= f[i+1]
证明:
假设 f[i] > f[ i + 1 ]
那么必定有一个点k(k<i)使得i+1点是从k点跳过来的(显然这样不可能k=i,这样的话f[i+1] > f[i])
但是既然 k 点能够跳到i+1点,那么k点也一定能够跳到i点,那么此时f[i]就可以变成从k点跳过来,此时就找到了一个比上一个f[i]更小值的步数,且这个步数最大等于f[i+1],也就是推出f[i]<=f[i+1]
与假设矛盾,所以 f[i] > f[i+1] 不成立
综上所述: f[i] <= f[i+1]

因为有 f[i] <= f[i+1]的性质存在
而 f[i] = f[j]+1 所以我们找到一个尽可能远离i的j最好

class Solution {
public:
    int jump(vector<int>& nums) {
        int n = nums.size();
        vector<int> f(n+1);
        f[0] = 0;
        int last_node = 0;
        for(int i=1;i<n;i++){
            while(last_node + nums[last_node] < i) last_node++;
            //因为有 f[i] <= f[i+1]的性质存在
            //而 f[i] = f[j]+1  所以我们找到一个尽可能远离i的j最好
            f[i] = f[last_node] + 1;
        }
        return f[n-1];
    }
};

跳跃游戏(贪心)

在这里插入图片描述

class Solution {
public:
    bool canJump(vector<int>& nums) {
        int max_length = 0; //max_length表示能够跳跃的最大的长度
        for(int i=0;i<nums.size();i++){
            if(max_length < i) return false;//如果跳不到i了直接返回false
            max_length = max(max_length,i+nums[i]);
        }
        return true;
    }
};

46,47全排列(dfs)

在这里插入图片描述
这个题不含有重复的元素

class Solution {
public:
    vector<vector<int>> res;
    vector<int> path;
    map<int,bool> st;
    void dfs(vector<int>& nums,int depth)
    {
        
        if(depth==nums.size()){
            res.push_back(path);
            return;
        }
        for(int i=0;i<nums.size();i++){
            if(st[nums[i]]) continue;
            st[nums[i]] = true;
            path.push_back(nums[i]);
            dfs(nums,depth+1);
            path.pop_back();
            st[nums[i]] = false;

        }

    }

    vector<vector<int>> permute(vector<int>& nums) {
        int n = nums.size();
        for(int i=0;i<n;i++) st[nums[i]] = false;
        dfs(nums,0);
        return res;
    }
};

在这里插入图片描述
这个题含有重复的元素
在这里插入图片描述
总而言之,为了避免重复序列的出现,对于比如nums中有 1 1 1
那么当第一个1被用了之后,第二个1我们让他只能够排在第一个1的后面,同理,第三个1只能排在第二个1的后面
也就是每一次排一个数的时候,看一下这个数有没有被用过

class Solution {
public:
    vector<vector<int>> res;
    vector<int> path;
    vector<bool> st;
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        st = vector<bool>(nums.size(),false);
        path = vector<int>(nums.size());
        dfs(nums,0);
        return res;
    }

    void dfs(vector<int>& nums,int u)//u代表当前已经排列完几个节点了
    {
        if(u==nums.size()){
            res.push_back(path);
            return;
        }
        for(int i=0;i<nums.size();i++){
            if(!st[i]){//首先nums中的i号节点需要先没用过才行

            //如果nums[i]不是这个数值第一次被用,那么就先不排
            //就是比如说有 1 1 1 2 2 这样的我们每次用的1都是1 1 1 按顺序使用的
            // 必须先用没用过的1 再用下面的
                if(i>0 && nums[i]==nums[i-1] && !st[i-1]) continue;
            //只有这个数值是第一次被排列我们才去排列
            //换言之,如果这个数是此数值序列中的第一个
            //或者这个数值不是序列中此类数值的第一个,但是这个数的前一个数i-1已经被排过了
            //我们就可以继续排i号这个数了
                st[i] = true;
                path[u] = nums[i];
                dfs(nums,u+1);
                st[i] = false;
                
            }
        }

    }
};
class Solution {
public:
    vector<bool> st;
    vector<int> ans;
    vector<vector<int>> res;
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        int n = nums.size();
        sort(nums.begin(),nums.end());
        st = vector<bool>(n,false);
        dfs(nums,0);
        return res;
    }

    void dfs(vector<int>& nums, int u)
    {
        if(u==nums.size())
        {
            res.push_back(ans);
            return;
        }
        for(int i=0;i<nums.size();i++){
            if(st[i]) continue;
            if(i > 0 && nums[i]==nums[i-1] && !st[i-1]) continue;

            ans.push_back(nums[i]);
            st[i] = true;
            dfs(nums,u+1);
            st[i] = false;
            ans.pop_back();
        }
    }
};

50 POW(x,n)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

class Solution {
public:
    double myPow(double x, int n) {
        typedef long long LL;
        bool flag = false;
        if(n==0) return 1;
        if(n<0) flag = true;
        double res = 1;
        for(LL k = abs(LL(n));k;k>>=1)
        {
            if(k & 1) res *= x;//注意是k&1不是k&&1,看写成二进制的n的最后一位是0还是1
            x*=x;              //x记录的是 x^(2^i)
        }
        if(flag) res = 1/res;
        return res;
    }
};

n皇后(dfs)

在这里插入图片描述

class Solution {
public:
    int n;
    vector<bool> row;
    vector<bool> col;
    vector<bool> dg;
    vector<bool> rdg;
    vector<vector<string>> res;
    vector<string> path;
    vector<vector<string>> solveNQueens(int _n) {
        n = _n;
        row = vector<bool>(n);
        col = vector<bool>(n);
        dg = vector<bool>(2*n);
        rdg = vector<bool>(2*n);
        path = vector<string>(n,string(n,'.'));
        dfs(0);
        return res;
    }
    void dfs(int u){//u表示现在搜索到第几行了
        if(u==n){
            res.push_back(path);
            return;
        }

        //遍历这一行上的每个位置
        for(int i=0;i<n;i++){
            if(!col[i] && !row[u] && !dg[u+i] && !rdg[u-i+n]){
                col[i] = true;
                row[u] = true;
                dg[u+i] = true;
                rdg[u-i+n] = true;
                path[u][i] = 'Q';
                dfs(u+1);
                col[i] = false;
                row[u] = false;
                dg[u+i] = false;
                rdg[u-i+n] = false;
                path[u][i] = '.';
            }
        }

    }
};

在这里插入图片描述

class Solution {
public:
    int n;
    vector<bool> row;
    vector<bool> col;
    vector<bool> dg;
    vector<bool> rdg;
    vector<vector<string>> res;
    vector<string> path;
    int totalNQueens(int _n) {
        n = _n;
        row = vector<bool>(n);
        col = vector<bool>(n);
        dg = vector<bool>(2*n);
        rdg = vector<bool>(2*n);
        path = vector<string>(n,string(n,'.'));
        dfs(0);
        return res.size();
    }
    void dfs(int u){//u表示现在搜索到第几行了
        if(u==n){
            res.push_back(path);
            return;
        }

        //遍历这一行上的每个位置
        for(int i=0;i<n;i++){
            if(!col[i] && !row[u] && !dg[u+i] && !rdg[u-i+n]){
                col[i] = true;
                row[u] = true;
                dg[u+i] = true;
                rdg[u-i+n] = true;
                path[u][i] = 'Q';
                dfs(u+1);
                col[i] = false;
                row[u] = false;
                dg[u+i] = false;
                rdg[u-i+n] = false;
                path[u][i] = '.';
            }
        }

    }
};

最大子序和(dp)

在这里插入图片描述
f[ i ] 表示所有以nums[ i ]结尾的区间的集合方案的最大值
这个集合又可划分为两大类,区间长度为1(即包含nums[i]这个数)
区间长度大于1

class Solution {
public:
    vector<int> f;
    int maxSubArray(vector<int>& nums) {
        int n = nums.size();
        f = vector<int>(n);
        f[0] = nums[0];
        for(int i=1;i<n;i++){
            f[i] = max(nums[i],f[i-1]+nums[i]);
        }
        int res = -1e5;
        for(int i=0;i<n;i++) res = max(res,f[i]);
        return res;
    }
};

在这里插入图片描述
当还要输出这个序列起始和终止的数字时

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e4 + 10;
int n;
int nums[N];
int f[N],i_left[N]; //f[i]表示以nums[i]结尾的序列最大和
                  //left[i]表示以nums[i]结尾的序列的起始位置

int main()
{
    cin >> n;
    for(int i=0;i<n;i++) cin >> nums[i];
    f[0] = nums[0];
    i_left[0] = 0;
    int res = -1;
    int l,r;
    for(int i=1;i<n;i++){
        f[i] = nums[i];
        i_left[i] = i;
        if(f[i-1]+nums[i] >= f[i]){
            f[i] = f[i-1] + nums[i];
            i_left[i] = i_left[i-1];
        }
        if(f[i] > res){
            res = f[i];
            l = nums[i_left[i]];
            r = nums[i];
        }
    }
    if(res < 0){
        res = 0;
        l = nums[0];
        r = nums[n-1];
    }
    cout << res <<" "<<l << " "<< r << endl;
    return 0;
}

第k个排列

在这里插入图片描述
这种搜索方法排出来的本来就是按照字典序排的了

class Solution {
public:
    vector<string> res;
    string path;
    vector<bool> st;
    int n;
    string getPermutation(int _n, int k) {
        n = _n;
        st = vector<bool>(n+1,false);
        dfs(0);
        return res[k-1];
    }
    void dfs(int u)
    {
        if(u==n){
            res.push_back(path);
            return;
        }
        for(int i=1;i<=n;i++){
            if(st[i]) continue;
            st[i] = true;
            path.push_back(i + '0');
            dfs(u+1);
            path.pop_back();
            st[i] = false;
        }
    }
};

62不同路径(dp)

在这里插入图片描述

class Solution {
public:
    int uniquePaths(int m, int n) {
        vector<vector<int>> f(m, vector<int>(n, 0)); // 初始化为 0
        for(int i=0;i<n;i++) f[0][i] = 1;
        for(int i=0;i<m;i++) f[i][0] = 1;
        for(int i = 1; i < m; i++ )
            for(int j = 1;j<n;j++)
                f[i][j] = f[i-1][j] + f[i][j-1];
        return f[m-1][n-1];

    }
};

在这里插入图片描述
本题与上题的区别就是有的方格有障碍物的存在

class Solution {
public:
    int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
        int m = obstacleGrid.size();
        int n = obstacleGrid[0].size();
        vector<vector<int>> f(m,vector<int>(n,0));
        
        for(int i=0;i<m;i++){
            if(obstacleGrid[i][0]==1) break;//之后的格子都到不了了,都设置成0
            f[i][0] = 1;
        }
        
        for(int i=0;i<n;i++){
            if(obstacleGrid[0][i]==1) break;
            f[0][i] = 1;
        }
        //只需要判断一下这个格子是不是障碍物,是的话设为0,否则设为f[i-1][j]+f[i][j-1]
        for(int i=1;i<m;i++){
            for(int j=1;j<n;j++){
                if(obstacleGrid[i][j]==1) f[i][j] = 0;
                else{
                    f[i][j] = f[i-1][j] + f[i][j-1];
                }
            }
        }
        
        return f[m-1][n-1];
    }
};

64最小路径和(dp)

在这里插入图片描述

class Solution {
public:
    int minPathSum(vector<vector<int>>& grid) {
        int m = grid.size();
        int n = grid[0].size();
        vector<vector<int>> f(m,vector<int>(n,0));
        f[0][0] = grid[0][0];
        for(int i=1;i<m;i++) f[i][0] = f[i-1][0] + grid[i][0];
        for(int i=1;i<n;i++) f[0][i] = f[0][i-1] + grid[0][i];
        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];
    }
};

97复原IP地址

在这里插入图片描述

class Solution {
public:
    vector<string> res;
    vector<string> restoreIpAddresses(string s) {
        dfs(s,0,0,"");
        return res;
    }
    //u表示当前搜索到了哪一个位置,k表示当前已经分割出了几个数字
    void dfs(string& s,int u,int k,string path)
    {
        if(u==s.size()){
            if(k==4){
                path.pop_back();
                res.push_back(path);
            }
            return;
        }
        if(u!=s.size() && k==4) return; //如果已经得到四部分数字但是却还没划分完成直接剪枝

        int num = 0;
        for(int i = u; i < s.size(); i++)
        {
            if(i>u && s[u]=='0') break;
            num = num*10 + s[i]-'0';
            if(num<=255) dfs(s,i+1,k+1,path + to_string(num) + '.');
            else break;
        }
    }
};

71简化路径

在这里插入图片描述

/***
我们先把两个 /   /  之间的内容取出来,那么取出来的内容总共有几种情况:
.  ,  ..   ,  file_name  ,  空
如果/  /  之间的是空或者.那么不做操作
如果读出来的是文件名,入栈
如果读出来的是..  如果栈不为空就退栈
最后栈中的元素就是当前的文件路径
***/
class Solution {
public:
    string simplifyPath(string path) {
        int n = path.size();
        vector<string> res;
        stack<string> st;
        for(int i=0;i<n;)
        {
            string temp = "";
            int j = i + 1;
            while(j < n && path[j] != '/') temp += path[j++];
            i = j;
            res.push_back(temp);
        }
        for(int i=0;i<res.size();i++){
            if(res[i] == "" || res[i]==".") continue;
            else if(res[i] == ".."){
                if(!st.empty()) st.pop();
            }
            else st.push(res[i]);
        }
        string ans = "";
        while(!st.empty()){
            ans = "/" + st.top() + ans;
            st.pop();
        }
        if(ans=="") ans = "/";
        return ans;
    }
};

74搜索二维矩阵

在这里插入图片描述

/***
考虑把这个矩阵虚拟展开成一个一维的矩阵然后就可以用二分来做了
总共0~mn-1个位置
然后对于在一维数组中的 i 号位置影射到二维数组中的位置就是 (i/m,i%m)
***/

class Solution {
public:
    bool searchMatrix(vector<vector<int>>& matrix, int target) {
        if(matrix.empty() || matrix[0].empty()) return false;
        int n = matrix.size();
        int m = matrix[0].size();
        int l = 0, r = m*n-1;
        while(l < r)
        {
            int mid = (l+r)/2;
            if(matrix[mid/m][mid%m] >= target) r = mid;
            else l = mid + 1;
        }
        if(matrix[r/m][r%m]==target) return true;
        return false;
    }
};

75颜色分类

在这里插入图片描述
在这里插入图片描述
总的来说就是用三个指针来维护,j指向第一个1出现的位置, 0 ~ j-1 都是0
k指向2的部分的前一个位置也就是说 k+1 ~ nums.size()-1 这些位置都是2

我们用i来扫描数组
如果nums[i] = 0 , 那么swap(nums[j], nums[i]) 然后j++ , i++
如果nums[i] = 2, 那么swap(nums[i], nums[k]) 然后k–,此时就不要i++了,因为我们交换过来的东西可能是0,不一定是1
如果nums[i] = 1 , 那么i++即可
然后最终i = k + 1的时候就结束了(注意i=k的时候还不能结束,因为有可能k指向的这个位置他是0还得再换一次,即使是1那么也无妨再i++后当i = k+1时退出即可)

class Solution {
public:
    void sortColors(vector<int>& nums) {
        for(int i=0,j=0,k=nums.size()-1;i<=k;)
        {
            if(nums[i]==0) swap(nums[i++],nums[j++]);
            else if(nums[i]==2) swap(nums[i],nums[k--]);
            else i++;
        }
    }
};

77组合

在这里插入图片描述

/***
组合问题比较麻烦的地方在于判重问题,但是我们可以规定某种选取规则,比如选的数不能比之前选的数小
***/
class Solution {
public:
    vector<int> ans;
    vector<vector<int>> res;
    vector<vector<int>> combine(int n, int k) {
        dfs(n,k,1);
        return res;
    }
    void dfs(int n,int k,int start)
    {//n表示从1~n中选, k 表示还能够选的数的个数, start表示最小从这个数开始选
        if(k==0)
        {
            res.push_back(ans);
            return;
        }
        for(int i=start;i<=n;i++){
            ans.push_back(i);
            dfs(n,k-1,i+1);
            ans.pop_back();
        }
    }
};

78子集

在这里插入图片描述

class Solution {
public:
    vector<int> ans;
    vector<vector<int>> res;
    vector<vector<int>> subsets(vector<int>& nums) {
        dfs(nums,0);
        return res;
    }
    void dfs(vector<int>& nums,int depth)
    {
        if(depth==nums.size())
        {
            res.push_back(ans);
            return;
        }

        dfs(nums,depth+1); //不选这个数
        ans.push_back(nums[depth]); //选这个数
        dfs(nums,depth+1);
        ans.pop_back();
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

新城里的旧少年^_^

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值