2021-复习

4 篇文章 0 订阅
4 篇文章 0 订阅

1、剑指 Offer 14- I. 剪绳子

给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]…k[m-1] 。请问 k[0]k[1]…*k[m-1] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。

class Solution {
public:
// 减绳子 : dp[i]表示长度为i的绳子剪成m段的最大乘积,这一题m可以不用参与到考虑之中
// 第一段减掉j,那么剩下i-j的长度,你可以选择减也可以选择不剪, 取最大值 max(max(j*(i-j),j*dp[i-j]),dp[i]),这就是状态转移方程
    int cuttingRope(int n) {

        vector<int> dp(n+1,0);
        dp[1] = 0;
        dp[2] = 1;

        for(int i = 3; i<=n; ++i){
            for(int j  = 2; j<i; ++j){  //从2开始,如果剪成1,那么对于乘积来说没有增益
                dp[i] = max(dp[i],max(j*(i-j),j*dp[i-j]));
            }
        }

        return dp[n];
    }
};

2、剑指 Offer 14- II. 剪绳子 II

给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]…k[m - 1] 。请问 k[0]k[1]…*k[m - 1] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。

class Solution {
public:
// 如果需要取余,那么不能使用动态规划来做,再循环中max取余,会导致结果错误
// 只能用贪心来做 
    int cuttingRope(int n) {
        
        if(n<=3) return n-1;
        long res = 1;

        while(n >4){
            res *= 3;
            n = n-3;
            res = res % (1000000007);
        }

        //循环结束后,n为1 2 3 或者 4,如果要获得最大值,那么直接乘以n就是最大的
        return (n*res)%1000000007;

    }
};

3、剑指 Offer 20. 表示数值的字符串

请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。
数值(按顺序)可以分成以下几个部分:
若干空格
一个 小数 或者 整数
(可选)一个 ‘e’ 或 ‘E’ ,后面跟着一个 整数
若干空格
小数(按顺序)可以分成以下几个部分:
(可选)一个符号字符(’+’ 或 ‘-’)
下述格式之一:
至少一位数字,后面跟着一个点 ‘.’
至少一位数字,后面跟着一个点 ‘.’ ,后面再跟着至少一位数字
一个点 ‘.’ ,后面跟着至少一位数字
整数(按顺序)可以分成以下几个部分:
(可选)一个符号字符(’+’ 或 ‘-’)
至少一位数字

class Solution {
public:
// 表示数值的字符串
    bool isNumber(string s) {
        int idx = 0;
        int len = s.size();
        //去除前置空格
        while(idx < len && s[idx] == ' ') idx++;

        //设置四个flag,用于判断
        bool hasNum = false, hasDot = false, hasE = false, hasSign = false;

        //以e作为分界点
        while(idx < len){
            //符号的处理
            if(s[idx]>='0' && s[idx] <= '9'){
                hasNum = true;
            }else if(s[idx] == '-' || s[idx] == '+'){
                if(hasSign || hasNum || hasDot)
                    return false;
                hasSign = true;
            }else if(s[idx] == '.'){
                if(hasDot || hasE) return false;
                hasDot = true;
            }else if(s[idx] == 'e' || s[idx] == 'E'){
                if(hasE || !hasNum) return false;  //在e之前一定要有数字
                hasNum = false;
                hasDot = false;
                hasSign = false;
                hasE = true;
            }else break;  //后置空格还要处理

            idx++;
        } 

        while(idx < len && s[idx] == ' ') idx++;

        return hasNum && (idx == len);
    }
};

4、剑指 Offer 16. 数值的整数次方

实现 pow(x, n) ,即计算 x 的 n 次幂函数(即,xn)。不得使用库函数,同时不需要考虑大数问题。

class Solution {
public:
// 数值的整数次方,快速幂算法
    double myPow(double x, int b) {
        double res = 1;
        if(x == 0) return 0;
        if(b == 0) return 1;
        long n = (long)b;

        if(n < 0){
            n = -n; // 防止溢出
            x = 1/x;
        }

        while(n>0){
            if(n&1){
                res = res * x;
            }
            x = x * x;  // x等于x^2, x = (x^2)*x^2, x = x4*x^4; ....
            n = n>>1;
        }

        return res;
    }
};

5、剑指 Offer 35. 复杂链表的复制

请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null。

class Solution {
public:
//  复杂链表的复制
    Node* copyRandomList(Node* head) {
        unordered_map<Node*,Node*> map;

        Node *dup = head, *cur = head;

        //建立旧链表节点到新链表节点的映射
        while(head){
            map[head] = new Node(head->val);
            head = head->next;
        }

        //由于新旧节点之间已经建立了映射,建立新结点的指向关系的时候,根据之前建立的映射即可建立指向
        while(cur){
            map[cur]->next = map[cur->next];
            map[cur]->random = map[cur->random];
            cur = cur->next;
        }

        return map[dup];
    }
};

6、92. 反转链表 II

给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 。

class Solution {
public:
    ListNode* reverseBetween(ListNode* head, int left, int right) {
        ListNode *dumy = new ListNode(-1);
        dumy->next= head;
        ListNode *prev = dumy;

        ListNode *a = dumy, *b = dumy;
        int i = 0;
        for(int i = 0; i<left-1; ++i){
            if(a == nullptr) return nullptr;
            a = a->next;   //上一个节点
        }
        for(int i = 0; i<right; ++i){
            if(b == nullptr) return nullptr;
            b = b->next;  // 尾节点
        }

        a->next = help(a->next,b->next);
        
        return dumy->next;
    }

    ListNode *help(ListNode *head, ListNode *tail){
        ListNode  *prev = tail;
        ListNode *next = nullptr;
        while(head != tail){
            next = head->next;
            head->next = prev;
            prev = head;
            head = next;
        }
        return prev;
    }
};

7、 剑指 Offer 36. 二叉搜索树与双向链表

输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。

class Solution {
public:
    Node* treeToDoublyList(Node* root) {
        if(root == nullptr) return root;
        help(root);
        head->left = pre;
        pre->right = head;
        return head;
    }
    Node *pre, *head;

    void help(Node *cur){
        if(cur == nullptr) return;
        //中序遍历 
        help(cur->left);
        //记录前一个节点 pre,然后和当前节点坐指向,最后在主函数中修改head和pre的指向
        if(pre == nullptr) head = cur;
        else pre->right = cur;
        cur->left = pre;
        pre = cur;

        help(cur->right);
    }
};

8、剑指 Offer 31. 栈的压入、弹出序列

输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如,序列 {1,2,3,4,5} 是某栈的压栈序列,序列 {4,5,3,2,1} 是该压栈序列对应的一个弹出序列,但 {4,3,5,1,2} 就不可能是该压栈序列的弹出序列。

class Solution {
public:
// 回溯可做,直接循环
    bool validateStackSequences(vector<int>& pushed, vector<int>& popped) {
        stack<int> st;
        int idx = 0;
        /* 将数组入栈,然后判断是否和poped中的第一个元素相等,如果是,那么直接*/
        for(auto num:pushed){
            st.push(num);
            while(!st.empty() && st.top() == popped[idx]){
                st.pop();
                idx++;
            }
        }
        return st.empty();
    }
};

9、剑指 Offer 39. 数组中出现次数超过一半的数字

class Solution {
public:
// 数组中出现次数超过一半的数字 摩尔投票法
/*
    众数的投票数为1,非众数的投票数为-1,那么总的投票数一定是大于0
    当vot == 0的时候,那么在剩下的区间中,众数依然没有变。
*/
    int majorityElement(vector<int>& nums) {
        int vot = 0, x = 0;
        for(int i  = 0; i<nums.size(); ++i){
            if(vot == 0) x = nums[i];   
            if(nums[i] == x) vot++;  
            else vot--;
        }
        return x;
    }
};

10、4. 寻找两个正序数组的中位数

给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。

class Solution {
public:
// 寻找两个正序数组的中位数:找第k大的数
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        int m = nums1.size(), n = nums2.size();
        int k1 = (m+n+1)/2;
        int k2 = (m+n+2)/2;

        if((m+n)&1)
            return help(nums1,0,m-1,nums2,0,n-1,k1);
        else 
            return (help(nums1,0,m-1,nums2,0,n-1,k1) + help(nums1,0,m-1,nums2,0,n-1,k2))/2.0;
    }
    // 转换为找第k小的数字
    int help(vector<int> &nums1, int start1, int end1, vector<int> &nums2, int start2, int end2,int k){
        int len1 = end1-start1+1;
        int len2 = end2-start2+1;
        if(len1 >len2) return help(nums2,start2,end2,nums1,start1,end1,k);

        //base case
        if(len1 == 0) return nums2[start2+k-1];
        if(k == 1) return min(nums1[start1],nums2[start2]);

        int i = min(end1,start1+k/2-1);
        int j = min(end2,start2+k/2-1);

        if(nums1[i] > nums2[j])
            return help(nums1,start1,end1,nums2,j+1,end2, k-(j-start2+1));
        else return help(nums1,i+1,end1,nums2,start2,end2,k-(i-start1+1));
    }
};

11、数字划分 ---- 需要注意的题型-》放苹果

将整数n分成k份,且每份不能为空,任意两种划分方案不能相同(不考虑顺序)。
例如:n=7,k=3,下面三种划分方案被认为是相同的。
1 1 5
1 5 1
5 1 1
问有多少种不同的分法。

/*
将n个小球放到k个盒子中的情况总数 =
1. 至少有一个盒子只有一个小球的情况数 + 2. 所有的盒子都多余一个小球
那么
所有的盒子都多于一个小球:先在每个盒子中放一个小球,然后再分配n-k个球,因此为 f(n-k,k)
至少有一个盒子只有一个小球,那么先在某个盒子中放一个小球,因此为 f(n-1,k-1)
*/
int fun(int n,int k){
	if(n==0||n<k||k==0)return 0;
	else if(n==k||k==1) return 1; 
	else return fun(n-k,k)+fun(n-1,k-1); 
}

12、整数划分

将正整数n 表示成一系列正整数之和,n=n1+n2+…+nk, 其中n1>=n2>=…>=nk>=1 ,k>=1
正整数n 的这种表示称为正整数n 的划分。正整数n 的不同的划分个数称为正整数n 的划分数。

/*
	这一题和上一题相比,少了一个k的限制。那么其实k的最大值为n,所以将上一题改造为f(n,n)即可
*/

13、放苹果

把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?(用K表示)5,1,1和1,5,1 是同一种分法。

/*
	假设有n个苹果,k个盘子
	n<k: 那么一定有盘子空着的,f(n,k) = f(n,n);
	n>=k:
		分为两种情况,1、至少有一个盘子是空的,表示为 f(n,k-1)
		2、没有盘子空着,那么先在每个盘子放一个苹果,f(n-k,k)
		f(n,k) = f(n,k-1) + f(n-k,k)
*/

int apple(int n, int k){
// if(m == 0 || n==1) return 1 ;  //原解答
	if(n == 0) return 1;  //没有苹果
	if(k==1) return 1;   //一个盘子
	if(n<k) return f(n,n);
	return f(n,k-1) + f(n-k,k);
}

14、strStr() kmp

kmp算法


15、旋转数组的最小值

class Solution {
public:
    // 旋转数组的最小值: 这里是将mid和right进行比较,因为没有targer值,这点要注意,不要懵了
    int minNumberInRotateArray(vector<int> rotateArray) {
       int left = 0, right = rotateArray.size()-1;
        while(left<=right){
            int mid = left+(right-left)/2;
            if(rotateArray[mid] > rotateArray[right])
                left = mid+1;
            else if(rotateArray[mid] < rotateArray[right]) 
                right = mid;  //不能写为mid-1,如果right刚好指向最小值呢?那不就将最小值过滤了么
            else right--;  //这个时候最小值可能在左边也可能在右边,要进行先行搜索
            //可以写为left++么?不可以,因为如果不能保证现有区间内一定有一个值和left相同,如果left刚好是最小值呢,那不就gg了
        }
        return rotateArray[left];  // 为啥是left呢?因为最终一定会mid,left,right指向同一个元素,此时right需要--;left才是真正的结果
    }
};

16、给定一个二进制数组 nums , 找到含有相同数量的 0 和 1 的最长连续子数组,并返回该子数组的长度。

class Solution {
public:
 // 和为0的最长连续子数组
    int findMaxLength(vector<int>& nums) {
        for(int i = 0; i<nums.size();++i)
            if(nums[i] == 0) nums[i] = -1;
        int sum_j = 0;
        int start = 0;
        int finish = 0;
        // 分别记录前缀和的最大和最小索引
        unordered_map<int,int> memMin;
        unordered_map<int,int> memMax;

        for(int i = 0; i<nums.size(); ++i){
            sum_j += nums[i];
            if(memMin.count(sum_j)){
                memMax[sum_j] = max(memMax[sum_j],i);
            }else{
                memMin[sum_j] = i;
                memMax[sum_j] = i;
            }
        }

        for(auto it = memMin.begin(); it != memMin.end(); ++it){
            int minIndex = it->second;
            int maxIndex = memMax[it->first];
            if(it->first == 0)  //如果前缀和为0,那么只需要记录最大的index就可以了,最小值设置为-1(不能设置为0,因为我们是包含0号索引的)
                minIndex = -1;
            if(maxIndex-minIndex > finish-start){
                start = minIndex;
                finish = maxIndex;
            }
        }
        return finish-start;
    }   
};

17、判断ip地址的有效性

编写一个函数来验证输入的字符串是否是有效的 IPv4 或 IPv6 地址。
如果是有效的 IPv4 地址,返回 “IPv4” ;
如果是有效的 IPv6 地址,返回 “IPv6” ;
如果不是上述类型的 IP 地址,返回 “Neither” 。
IPv4 地址由十进制数和点来表示,每个地址包含 4 个十进制数,其范围为 0 - 255, 用(".")分割。比如,172.16.254.1;
同时,IPv4 地址内的数不会以 0 开头。比如,地址 172.16.254.01 是不合法的。
IPv6 地址由 8 组 16 进制的数字来表示,每组表示 16 比特。这些组数字通过 (":")分割。比如, 2001:0db8:85a3:0000:0000:8a2e:0370:7334 是一个有效的地址。而且,我们可以加入一些以 0 开头的数字,字母可以使用大写,也可以是小写。所以, 2001:db8:85a3:0:0:8A2E:0370:7334 也是一个有效的 IPv6 address地址 (即,忽略 0 开头,忽略大小写)。
然而,我们不能因为某个组的值为 0,而使用一个空的组,以至于出现 (:😃 的情况。 比如, 2001:0db8:85a3::8A2E:0370:7334 是无效的 IPv6 地址。
同时,在 IPv6 地址中,多余的 0 也是不被允许的。比如, 02001:0db8:85a3:0000:0000:8a2e:0370:7334 是无效的。

// 这一题写的就是纯逻辑做好判断:首先是分隔符的个数要判断,然后是字符串的大小,长度要判断好,是否是0开头要判断好
class Solution {
public:
    string validIPAddress(string IP) {
        string isIP4 = "IPv4", isIP6 = "IPv6", neither = "Neither";

        if(count(IP.begin(),IP.end(),'.')) return validIP4(IP);
        else return validIP6(IP);
        
        return neither;
    }

    string validIP4(string IP){
        int index = 0;
        string tmp;
        int dotCnt = 0;
        while(index < IP.size()){
            if(IP[index] == '.'){
                int integer = atoi(tmp.c_str());  // 如果越界返回-1
                //判断是否以0开头 判断两个点之间是否有数字  判断是否越界
                if(++dotCnt == 4 || tmp.size() == 0 || (tmp[0] == '0' && tmp.size() != 1) || !(integer>=0 && integer<=255)) 
                    return "Neither";  
                tmp = "";
            }else if(IP[index] >= '0' && IP[index] <= '9'){
                tmp += IP[index];
            }else 
                return "Neither";
            index++;
        }
        if(tmp.size() == 0 || (tmp[0] == '0' && tmp.size() != 1) || atoi(tmp.c_str()) > 255 || dotCnt != 3) 
            return "Neither";  
        return "IPv4";
    }

    string validIP6(string IP){
        if(IP.size() == 0) return "Neither";
        int index = 0;
        string pattern = "0123456789abcdefABCDEF";
        string tmp="";
        int cnt = 0;

        while(index < IP.size()){
            if(IP[index] == ':'){
                if(++cnt == 8 || tmp.size() == 0 || tmp.size() > 4) return "Neither";
                tmp = "";
            }else if(count(pattern.begin(),pattern.end(),IP[index]) == 1){
                tmp += IP[index];
            }else 
                return "Neither";
            index++;
        }
        if(tmp.size() == 0 || tmp.size() > 4 || cnt != 7) 
            return "Neither";
        return "IPv6";
    }
};

18、atoi函数实现

class Solution {
public:
// 前置空格,符号,非法字符,溢出
    int strToInt(string str) {
        int idx = 0;
        int len = str.size();
        int flag = 1;
        int res = 0;

        // space
        while(idx<len && str[idx] == ' ') idx++;
        //sign
        if(str[idx] == '-'){
            flag = -1;
            idx++;
        }else if(str[idx] == '+') idx++;

        while(idx < len){
            if(str[idx]<'0' || str[idx]>'9')
                return res*flag;
            int num = str[idx]-'0';
            if(res > INT_MAX/10 || (res == INT_MAX/10 && num > INT_MAX%10))
                return flag==-1?INT_MIN:INT_MAX;
            res = 10*res + num;
            idx++;
        }
        return res*flag;
    }
};

19、正则表达式匹配,通配符匹配

// 正则表达式
class Solution {
public:
    bool isMatch(string s, string p) {
        return helper(s,0,p,0);
    }
    map<pair<int,int>,bool> mem;
    bool helper(string s, int i, string p, int j){
        if(j == p.size()) return s.size()==i;
        if(mem.count(make_pair(i,j))) return mem[make_pair(i,j)];

        bool cur = (i<s.size()) && (s[i]==p[j] || p[j]=='.');

        // j<=p.size()-2 因为“a*”这种,如果没有等于,那么就不会进行*的判断了
        if(j<=p.size()-2 && p[j+1] == '*'){
            bool noMatch = helper(s,i,p,j+2);  
            bool oneMatch = cur && helper(s,i+1,p,j);
            mem[make_pair(i,j)] = noMatch || oneMatch;
        }else 
            mem[make_pair(i,j)] = cur && helper(s,i+1,p,j+1);
        
        return mem[make_pair(i,j)];
    }
};
// 通配符匹配,和正则表达式还是有点不同,
class Solution {
public:
    bool isMatch(string s, string p) {
        return doHelp(s,0,p,0);
    }
    map<pair<int,int>,int> mem;
    bool doHelp(string &s, int i, string &p, int j){

        if(j == p.size()) return s.size() == i;
        if(i == s.size()) return p.size() == j || (p[j] == '*' && doHelp(s,i,p,j+1));

        if(mem.count(make_pair(i,j))) return mem[make_pair(i,j)];
        //当前字符是否匹配
        bool ans = (i<s.size())&&((s[i] == p[j]) || (p[j] == '?'));

        if(p[j] == '*'){
            // 可以匹配0个,也可以匹配1个
            ans = doHelp(s,i,p,j+1) || doHelp(s,i+1,p,j);
            mem[make_pair(i,j)] = ans;
            return ans;
        }

        mem[make_pair(i,j)] = ans && doHelp(s,i+1,p,j+1);
        return mem[make_pair(i,j)];
    }
};

20、回溯系列复习

子集

class Solution {
public:
    vector<vector<int>> subsets(vector<int>& nums) {
        vector<int> tmpStore;
        helper(nums,0,tmpStore);

        return res;
    }
vector<vector<int>> res;
    void helper(vector<int> &nums, int start, vector<int> &tmpStore){

        res.push_back(tmpStore);
        if(tmpStore.size() == nums.size()) 
            return;

        for(int i = start; i<nums.size(); ++i){
            // 做选择
            tmpStore.push_back(nums[i]);
            helper(nums,i+1,tmpStore);
            // 撤销选择
            tmpStore.pop_back();
        }
    }
};

21、动态规划系列复习

22、并查集复习

23、二分复习

在排序数组中查找元素的第一个和最后一个位置

class Solution {
public:
// 二分查找,查找第一个和最后一个位置
    vector<int> searchRange(vector<int>& nums, int target) {
        int left = searchLeft(nums,target);
        int right = searchRight(nums,target);

        return {left,right};
    }

    int searchLeft(vector<int> &nums, int target){
        int left = 0, right = nums.size()-1;

        while(left <= right){
            int mid = left + (right-left)/2;
            if(nums[mid] ==  target) right = mid-1;
            else if(nums[mid] > target) right = mid -1;
            else if(nums[mid] < target) left = mid + 1;
        }
        if(left >= nums.size() || nums[left] != target) return -1;
        return left;
    }

    int searchRight(vector<int> &nums, int target){
        int left = 0, right = nums.size()-1;

        while(left <= right){
            int mid = left + (right-left)/2;
            if(nums[mid] == target) left = mid + 1;
            else if(nums[mid] > target) right = mid-1;
            else if(nums[mid] < target) left = mid + 1;
        }
        if(right <0 || nums[right] != target) return -1;
        return right;
    }
};

24、大数相加,大数相乘,快速幂等小技巧

大数相加

class Solution {
public:
// 大数加法
// 有三个点需要特别注意的,再代码中已经标出
    string addStrings(string num1, string num2) {
        int carry = 0, sum = 0;
        int i = num1.size()-1, j = num2.size()-1;
        string res;

        while(i >= 0 || j >= 0){
            // 1、如果越界了就补0
            int n1 = i>=0? num1[i]-'0':0;
            int n2 = j>=0? num2[j]-'0':0;
            sum = n1 + n2 + carry;
            carry = sum/10;
            // 2、直接再字符串前面添加,后面就不用反转了
            res = to_string(sum%10) + res;
            i--;
            j--;
        }
        // 2、 最后还要判断carry是否是1
        return carry==1?'1'+res:res;
    }
};

大数相乘

class Solution {
public:
    string multiply(string str1, string str2) {
        if(str1 == "0" || str2 == "0") return "0";

        int len1 = str1.size(), len2 = str2.size();
        // 结果的最大长度为len1+len2
        vector<int> res(len1+len2,0);

        for(int i = len1-1; i>=0; --i){
            int n1 = str1[i]-'0';
            for(int j = len2-1; j>=0; --j){
                int n2 = str2[j]-'0';
                int sum = res[i+j+1]+n1*n2;
                res[i+j+1] = sum%10;
                res[i+j] += sum/10;
            }
        }
        string strRes;
        for(int i = 0; i<res.size(); ++i){
            if(i ==0 && res[i] == 0) continue;
            strRes += to_string(res[i]);
        }
        return strRes;
    }
};

25、不用运算符实现加法,位运算相关

不用运算符实现加法

class Solution {
public:
    int add(int a, int b) {
        // 不用运算符实现加法
        // ^ 没有进位的加法
        // & 就是进位的值
        while(b){
            // c++中负数不支持左移位
            int c = (unsigned int)(a&b)<<1;
            a = a^b;
            b = c;
        }
        return a;
    }
};

26、跳跃游戏

跳跃游戏1

class Solution {
public:
// 跳跃游戏
    bool canJump(vector<int>& nums) {
        int len = nums.size();
        if(len <= 1) return true;

        //vector<int> dp(nums.size(),0);  //nums[i]可以到达的最大索引
        //dp[0] = nums[0];
        int prev = nums[0];
        int res = prev;

        for(int i = 1; i<len-1; ++i){
            // 判断上一步是否能达到当前位置
            if(prev < i) return false;
            res = max(i + nums[i],prev);
            prev = res;
        }

        return res>=len-1;
    }
};

跳跃游戏2:找出能到达数组最后一个位置的最小跳跃次数

class Solution {
public:
    int jump(vector<int>& nums) {
        // 能跳跃到数组最后一个位置的最小跳跃次数
        int len = nums.size();
        if(len <= 1) return 0;

        int maxLen = nums[0];
        int tmp = maxLen;
        int step = 1;

        for(int i = 1; i<len-1; ++i){
            tmp = max(i+nums[i],tmp);  // 记录下一次能跳跃到的最大位置

            if(maxLen == i){ // 到达当前跳的最大位置,进行下一条,保证每一跳都是跳跃到最大的位置
                maxLen = tmp;
                step++;
            }
        }
        return step;
    }
};

滑动窗口

最小覆盖子串

class Solution {
public:
// 最小覆盖子串
    string minWindow(string s, string t) {
        unordered_map<char,int> need, win;
        for(auto c:t) need[c]++;
        int left = 0, right = 0;
        int valid = 0;
        int start = 0, len = s.size()+1;

        while(right < s.size()){
            // 向右收缩
            char c = s[right];
            right++;
            if(need.count(c)){
                win[c]++;
                if(need[c] == win[c])
                    valid++;
            }
            // 向左收缩,直到不满足条件
            while(valid == need.size()){
                if(right- left < len){
                    start = left;
                    len = right-left;
                }
                char d = s[left];
                left++;
                if(need.count(d)){
                    if(need[d] == win[d])
                        valid--;
                    win[d]--;
                }
            }
        }
        return len==s.size()+1?"":s.substr(start,len);
    }
};

所有可能的路径

class Solution {
public:
vector<vector<int>> res;
    vector<vector<int>> allPathsSourceTarget(vector<vector<int>>& graph) {
        vector<int> path;
        help(graph,0,path);
        return res;
    }

    void help(vector<vector<int>> &graph, int s, vector<int> &path){

        //加入路径
        path.push_back(s);

        if(s == graph.size()-1){
            res.push_back(path);
            path.pop_back();  //这里也要将最后一个节点pop出来
            return;
        }

        for(auto v:graph[s]){
            // 遍历邻接表
            help(graph,v,path);
        }

        path.pop_back();

    }
};

单调栈

下一个更大元素 II

class Solution {
public:
    vector<int> nextGreaterElements(vector<int>& nums) {
        stack<int> st;
        vector<int> res(nums.size());

        // 循环数组
        for(int i = nums.size()-1; i>=0; --i){
            st.push(nums[i]);
        }
        for(int i = nums.size()-1; i>=0; --i){
            
            while(!st.empty() && nums[i] >= st.top()){
                st.pop();
            }
            res[i] = st.empty()?-1:st.top();
            st.push(nums[i]);
        }

        return  res;
    }
};

每日温度

class Solution {
public:
// 每日温度: 单调栈使用
    vector<int> dailyTemperatures(vector<int>& temperatures) {
        vector<int> res(temperatures.size());
        stack<int> st;

        for(int i = temperatures.size()-1; i>=0; --i){
            while(!st.empty() && temperatures[i] >= temperatures[st.top()]){
                st.pop();
            }

            // 栈顶元素大于当前元素
            res[i] = st.empty()?0:(st.top()-i);

            st.push(i);  //因为要求索引的差值,所以这里直接存放索引,在while中利用索引再计算对应的值
        }
        return res;
    }
};

图的dfs

课程表

class Solution {
public:
// 主要判断这个课程表的图中是否有环存在

bool hasCircle = false;
    // s为遍历图的起始点
    void dfs(vector<vector<int>> &graph, int s, vector<bool> &visited, vector<bool> &onPath){

        if(onPath[s] == true)
        {
            hasCircle = true;
        }

        if(visited[s])
            return;

        /* 前序遍历代码位置 */

        visited[s] = true;
        onPath[s] = true;
        for(auto t:graph[s]){
            dfs(graph,t,visited,onPath);
        }
        onPath[s] = false;
        /* 后续遍历代码位置 */
    }

    bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
        // 建图: 领接表
        vector<vector<int>> graph(numCourses,vector<int>());
        for(auto pre:prerequisites){
            int from = pre[1];
            int to = pre[0];
            graph[from].push_back(to);
        }

        vector<bool> visited(numCourses,false);
        vector<bool> onPath(numCourses,false);

        // 不是所有的节点都相连,需要用for将所有节点都调用一次
        for(int i = 0; i<numCourses; ++i){
            dfs(graph,i,visited,onPath);
        }

        return !hasCircle;
    }
};

拓扑排序

课程表2

class Solution {
public:
// 拓扑排序:必须要是一个有向无环图,则图的拓扑排序就是将这个图拉平,同时所有的箭头指向相同
// 所以:1、首先要进行是否有环的检测 2、进行拓扑排序, 图的后序遍历的逆序就是拓扑排序的结果
//(后序遍历相当于是先遍历子节点然后再遍历父节点,相当于父节点依赖于子节点。 而拓扑排序的结果是所有节点指向向右,也就是子节点依赖于父节点
// 因此他们的依赖关系是相反的,拓扑排序是后序遍历结果的逆序)
// 拓扑排序的结果就是可行的一个课程安排
    vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {
        // 建领接表
        vector<vector<int>> graph(numCourses);
        for(auto pre: prerequisites){
            int from = pre[1];
            int to = pre[0];
            graph[from].push_back(to);
        }

        //判断是否有环
        vector<bool> onPath(numCourses);
        vector<bool> visited(numCourses);
            // 因为可能不是所有的节点都联通
        for(int i = 0; i<numCourses; ++i)
            dfs(graph, i, visited, onPath);
        if(hasCircle){
            // 有环,直接返回
            return {};
        }

        // 无环, 进行拓扑排序
        vector<bool> visited2(numCourses);
        for(int i = 0; i<numCourses; ++i){
            travase(graph,i,visited2);
        }

        return vector<int>(res.rbegin(),res.rend());
    }

    vector<int> res;
    void travase(vector<vector<int>>&graph, int s, vector<bool> &visited){
        if(visited[s])
            return;
        visited[s] = true;
        for(auto g: graph[s]){
            travase(graph, g, visited);
        }
        // 后序遍历结果
        res.push_back(s);
    }

    bool hasCircle = false;
    void dfs(vector<vector<int>> &graph, int s, vector<bool> &visited, vector<bool> &onPath){
        // 这个是否有环的判断要在是否遍历过之前判断
        if(onPath[s]){
            hasCircle = true;
        }

        if(visited[s]) {
            return;
        }
        
        onPath[s] = true;  //判断是否有环
        visited[s] = true;
        for(auto g:graph[s]){
            dfs(graph, g, visited, onPath);
        }
        onPath[s] = false;
    }
};

滑动窗口的最大值

vector<int> help(const vector<int>& num, unsigned int size) {
        vector<int> res;
        
        int left = 0, right = 0;
        int win = 0;
        priority_queue<node *> q;
        
        while(right < num.size()){
            int c = num[right];
            right++;
            win++;
            q.push(new node(c, right-1));
            
            if(win == size){
                node* tmp = q.top();
                res.push_back(tmp->val);
                // 用一个数组暂时存储,然后再放进去。将left的数据pop出来
                vector<node *> store;
                while(q.top()->index != left){
                    store.push_back(q.top());
                    q.pop();
                }
                q.pop();
                for(auto x: store)
                    q.push(x);
                left++;
                win--;
            }
        }
        
        return res;
    }

数组中的逆序对

class Solution {
public:
// 数组中逆序对: 看成一个排序问题,利用归并排序,排序过程中统计逆序对的个数
    int reversePairs(vector<int>& nums) {
        mergeSort(nums,0,nums.size()-1);
        return res;
    }

    int res = 0;
    void mergeSort(vector<int> &nums, int left, int right){
        if( left < right){
            int mid = left + (right-left)/2;
            mergeSort(nums,left,mid);
            mergeSort(nums,mid+1,right);
            merge(nums, left, mid, right);
        }
    }

    void merge(vector<int> &nums, int left, int mid, int right){
        int i = left, j = mid+1;
        int len = right-left+1;
        vector<int> tmp(len,0);
        int index = 0;

        while(i<=mid && j<=right){
            if(nums[i] <= nums[j]){
                tmp[index++] = nums[i++];
                res += (j-(mid+1));   // 需要计算的地方, 计算右边数组中比左边某个元素小的个数
            }else{
                tmp[index++] = nums[j++];
            }
        }

        while(i<=mid){
            tmp[index++] = nums[i++];
            res += (right-(mid+1)+1);  //需要计算的地方,右边数组已经遍历完全,那么左边数组的每个元素,都需要累加右边数据长度个逆序对
        }
        while(j<=right){
            tmp[index++] = nums[j++];
        }
        
        for(int k = 0; k<len; ++k){
            nums[left+k] = tmp[k];
        }
    }
};

min栈

class MinStack {
public:
    /** 这种写法是 O(n)的空间复杂度和O(1)的时间复杂度,怎么优化为O(1)的空间复杂度? 
    
    O(1)空间和O(1)时间复杂度:在栈中存放元素和min的差值
    */
    void push(int x) {
        st.push(x);
        if(stMin.empty() || stMin.top() >= x) stMin.push(x);
    }
    
    void pop() {
        if(st.top() == stMin.top())
            stMin.pop();
        st.pop();
    }
    
    int top() {
        if(st.empty())
            return -1;
        return st.top();
    }
    
    int min() {
        return stMin.top();
    }
private:
    stack<int> st, stMin;
};
// 最优的解法如何写
class MinStack {
public:
    /** initialize your data structure here. */
    MinStack() {

    }
    
    void push(int x) {
        if(st.empty()){
            st.push(0);
            minVal = x;
        }else{
            int sub = x-minVal;
            st.push(sub);       // 记录x和minVal的差值
            minVal = sub<0?x:minVal;  // 总是记录最小值 
        }
    }
    
    void pop() {
        int top = st.top();
        if(top<0){
            // 说明要弹出的这个值是最小值,那么需要当前的最小值和top值求得弹出这个值之后的最小值
            minVal = minVal - top;
        }
        st.pop();
    }
    
    int top() {
        return minVal + st.top();  // 有问题
        //return -1;
    }
    
    int min() {
        return minVal;
    }
private:
    stack<int> st;
    int minVal;
};

链表随机节点

class Solution {
public:
    /** @param head The linked list's head.
        Note that the head is guaranteed to be not null, so it contains at least one node. */
    Solution(ListNode* head) {
        this->head = head;
    }
    
    /** 对于一个这样的长度未知的链表来说,对于第i个节点,每次有1/i的概率选择该节点,1-1/i的概率保持原有的选择 
        如果是选择k个节点,那么就是k/i的概率选择该节点,1-k/i的概率保持原有的选择。

        因为:
        1/i * (1-1/(i+1) * (1-1/(i+2) * ... (1-1/n))) = 1/n
        也就是说,每个节点被选择的概率是相同的

    */
    int getRandom() {
        ListNode *cur = head;
        int res = -1;
        int i = 1;

        while(cur){
            if( rand()%i == 0){
                // 获取的值的范围是 0~i-1, 因此获取0的概率是 1/i
                // 也就是 1/i 的概率选择该节点, 否则保持原来的选择
                res = cur->val;
            }
            i++;
            cur = cur->next;
        }
        return res;
        // 随机选择k个如何写?
        int k = 5;
        ListNode *p = head;
        vector<int> resk(k);
        // 首先选k个
        for(int i = 0; i<k && p!=nullptr; ++i){
            resk[i] = p->val;
            p = p->next;
        }
        // 以 k/i的概率选择当前节点
        i = k;
        while(p){
            int r = rand()%i;
            if(r < k){
                resk[k] = p->val;
            }

            i++;
            p = p->next;
    }

private:
    ListNode *head;
};

随机数索引

class Solution {
public:
    Solution(vector<int>& nums) {
        this->nums = nums;
    }
    
    // 方法1: 暴力:用一个map或者二维数组存放索引然后直接rand获取一个随机的索引值
    // 方法2:水塘抽水算法
    int pick(int target) {
        int i = 1;
        int index = 0;
        int res = 0;

        while(index < nums.size()){
            if(nums[index] == target){
                int r = rand()%i;
                if(r == 0){
                    res = index;
                }
                i++;
            }

            index++;
        }

        return res;
    }
private:
    vector<int> nums;
};

丑数

class Solution {
public:
// 丑数:最小堆
    int nthUglyNumber(int n) {
        priority_queue<long, vector<long>, greater<long>> minQ; 
        unordered_map<int,int> deDup;  // 去重, 优先队列是可以重复的
        minQ.push(1);
        deDup[1] = 1;

        for(int i = 2; i<=n; ++i){
            long top = minQ.top();
            minQ.pop();
            for(auto factor: {2,3,5}){
                long tmp = top*factor;
                if(!deDup.count(tmp)){
                    minQ.push(tmp);
                    deDup[tmp] = 1;
                }
            }
        }

        return minQ.top();
    }
};

滑动窗口的最大值

class Solution {
public:
// 滑动窗口的最大值: 优先队列 或者 单调队列
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {

        return helperFunction(nums,k);

        vector<int> res;
        if(k == 0 || nums.size() == 0) return res;
        // 将窗口中的值放入到优先队列中
        priority_queue<pair<int,int>> q;
        for(int i = 0; i<k; ++i){
            q.push(make_pair(nums[i],i));
        }
        res.push_back(q.top().first);

        for(int i = k; i<nums.size(); ++i){
            q.push(make_pair(nums[i],i));
            // 如果当前的最大元素不在滑动窗口之内,就pop出来,那么留下来的就是最大的滑动窗口值
            while(q.top().second <= i-k){
                q.pop();
            }
            res.push_back(q.top().first);
        }
        return res;
    }

// 单调队列:
    vector<int> helperFunction(vector<int> &nums, int k){
        if(k == 0 || nums.size() == 0) return {};
        deque<int> d;
        for(int i = 0; i<k; ++i){
            while(!d.empty() && nums[i] >= nums[d.back()]){
                d.pop_back();
            }
            d.push_back(i);  // 放入的是索引
        }

        vector<int> res{nums[d.front()]};

        for(int i = k; i<nums.size(); ++i){
            // 保留最大元素的索引
            while(!d.empty() && nums[i] >= nums[d.back()]){
                d.pop_back();
            }
            d.push_back(i);
            // 提出窗口之外的最大值
            while(!d.empty() && d.front() <= i-k){
                d.pop_front();
            }
            res.push_back(nums[d.front()]);
        }

        return res;
    }
};

队列的最大值

class MaxQueue {
public:
    MaxQueue() {

    }
    
    int max_value() {
        // 单调队列
        if(dq.empty())
            return -1;
        return dq.front();
    }
    
    void push_back(int value) {
        // 单调队列:栈中的元素是单调的,本题中,是单调递减的
        while(!dq.empty() && dq.back() < value){
            dq.pop_back();
        }
        dq.push_back(value);
        MaxQ.push(value);
    }

    int pop_front() {
        if(MaxQ.empty()){
            return -1;
        }
        int front = MaxQ.front();
        if(front == dq.front())
            dq.pop_front();
        MaxQ.pop();
        return front;
    }
private:
    queue<int> MaxQ;
    deque<int> dq;
};

构建乘积数组

class Solution {
public:
// 构建乘积数组:不能使用除法: 首先构建res数组,利用前缀的特性,然后继续乘
    vector<int> constructArr(vector<int>& a) {
        vector<int> res(a.size(),1);
        if(a.size() == 0){
            return {};
        }
        // 矩阵的下三角
        for(int i = 1; i<res.size(); ++i){
            res[i] = res[i-1]*a[i-1];
        }

        // 从后向前计算上三角
        int tmp = a[a.size()-1];
        for(int i = a.size()-2; i>=0; --i){
            res[i] = res[i]*tmp;
            tmp = tmp * a[i];
        }

        return res;
    }
};

缺失的第一个正数

class Solution {
public:
// 缺失的第一个正数:原地哈希的思想,将对应的元素值映射到对应索引的位置
/*
    例如:将1映射到nums[1]的位置上, 2映射到nums[2]上
*/
    int firstMissingPositive(vector<int>& nums) {
        nums.push_back(-1);
        int len = nums.size();
        for(int i = 0; i<len; ++i){
            // 因为交换之后还可能需要继续交换,因此需要用循环不断判断和交换
            // nums[i] != nums[nums[i]] 的判断很重要,而不是 i != nums[i]: 写后面的可能会死循环,如输入[1,1]
            // 前者,包含的意思是nums[i]位置的元素不等于nums[i],而i位置的元素等于nums[i],可以进行交换使得nums[i]位置的元素等于nums[i]
            while(nums[i]>=0 && nums[i]<len && nums[i] != nums[nums[i]]){
                swap(nums[i], nums[nums[i]]);
            }
        }

        for(int i = 1; i<len; ++i){
            if(nums[i] != i){
                return i;
            }
        }
        return len;
    }
};

数字字符串转换成ip地址

class Solution {
public:
    /**
     * 
     * @param s string字符串 
     * @return string字符串vector
     */
    vector<string> restoreIpAddresses(string s) {
        // write code here
        string tmp;
        helper(s, 0, tmp, 0);
        return res;
    }
    
    vector<string> res;
    void helper(string s, int start, string tmp, int step){
        
        if(step==4 && start==s.size()){
            res.push_back(tmp.substr(0, tmp.size()-1));
            return;
        }
        
        if(step==4 || start==s.size()){
            return;
        }

        for(int i = start; i<start+3; ++i){
            
            if(i>=s.size()){
                return;
            }
            // 这里 i==start+2 是必须的,只有三个元素的时候进行比较才是正确的 "4">"255"
            if(i == start+2 && s.substr(start, i-start+1) > "255"){
                //cout<<"substr: "<<s.substr(start, i-start+1)<<" "<<tmp<<endl;
                return;
            }
            // 防止.01.出现
            if(s[start]=='0' && i != start){
                return;
            }
            
            tmp += s[i];
            tmp += '.';
            //cout<<tmp<<" "<<start<<" "<<step<<endl;
            helper(s, i+1, tmp, step+1);
            tmp = tmp.substr(0, tmp.size()-1);
        }
    }
};

最长有效括号

class Solution {
public:
    /**
     * 
     * @param s string字符串 
     * @return int整型
     */
    // 栈: 栈底保持为 最后一个没有被匹配的右括号的下标, 方下标是个小技巧\
    // 栈底的右括号坐标,主要是为了 )()()() 这种情况,就是刚好后面的匹配完,需要记录上次没有
    // 匹配的位置,计算最大值
    int longestValidParentheses(string s) {
        // write code here
        stack<int> st;
        st.push(-1);
        int res = 0;
        for(int i = 0; i<s.size(); ++i){
            if(s[i] == '('){
                st.push(i);
            }else{
                st.pop();
                if(st.empty()){
                    st.push(i);
                }else{
                    res = max(res,i-st.top());
                }
            }
        }
        return res;
    }
};

前缀树 trie

class Trie {
public:
    Trie() {
        isEnd = false;
        //cout<<sizeof(next)<<endl;
        memset(next, 0, sizeof(next));  // sizeof返回占有的字节数
    }
    
    void insert(string word) {
        // 构建前缀树,像是构建链表一样
        Trie *node = this;
        for(auto c: word){
            int idx = c-'a';
            if(node->next[idx] == nullptr){
                node->next[idx] = new Trie();
            }
            node = node->next[idx];
        }
        node->isEnd = true;
    }
    
    bool search(string word) {
        Trie *node = this;
        for(auto c: word){
            int idx = c-'a';
            if(node->next[idx] == nullptr){
                return false;
            }
            node = node->next[idx];
        }
        return node->isEnd;
    }
    
    bool startsWith(string prefix) {
        Trie *node = this;
        for(auto c: prefix){
            int idx = c-'a';
            if(node->next[idx] == nullptr){
                return false;
            }
            node = node->next[idx];
        }
        return true;
    }
private:
    bool isEnd;
    Trie *next[26]; // 指针数组,字母映射表,每个节点的下一个节点可能对应的字母,用对应的26个字母的位置表示
};

二叉树中的最大路径和

/**
 * 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 res = INT_MIN;
    int maxPathSum(TreeNode* root) {
        maxPathSumHelper(root);
        return res;
    }
    /* 定义这个函数为过root节点的最大路径值*/
    int maxPathSumHelper(TreeNode *root){
        // base case
        if(root == nullptr){
            return 0;
        }
        int left = maxPathSumHelper(root->left);
        int right = maxPathSumHelper(root->right);
        /*
            这里为什么要分开计算呢?
            res的值是 val, left+val, right+val 和 left+right+val 中的最大值,但是这个函数的返回值不能是left+right+val
            这种情况是横跨了当前节点,不能作为返回值,因为同一个节点在路径中至多出现一次
        */
        int cur = max(root->val, max(left+root->val, right+root->val));
        int tmp = max(cur, left+right+root->val);
        res = max(res, tmp);

        return cur;
    }
};

迪杰特斯拉算法(743. 网络延迟时间)

class State{
public:
    int id;
    int distFromStart;  // start到当前id节点的最短路径
    State(int _id, int _dist):id(_id),distFromStart(_dist){}
};

class cmp{
public:
    bool operator()(const State *a, const State *b){
        return a->distFromStart < b->distFromStart;
    }
};

class Solution {
public: 
// odijkstra
    int networkDelayTime(vector<vector<int>>& times, int n, int k) {
        vector<int> distTo = dijsktra(times, n, k);
        int res = -1;
        for(int i = 1; i<distTo.size(); ++i){
            if(distTo[i] == INT_MAX)
                return -1;
            res = max(res, distTo[i]);
        }
        return res;
    }
    vector<int> dijsktra(vector<vector<int>> &times, int n, int k){
        // build graph
        vector<vector<int>> graph(n+1, vector<int>());
        map<pair<int,int>, int> weight; 
        for(auto time: times){
            graph[time[0]].push_back(time[1]);
            weight[make_pair(time[0], time[1])] = time[2];
        }
        vector<int> distTo(n+1,INT_MAX);  //start到i节点的最短路径,初始的时候不可达
        distTo[k] = 0;

        priority_queue<State*, vector<State*>, cmp> pq;
        State *node = new State(k, 0);
        pq.push(node);
        while(!pq.empty()){
            // 选择最有潜力的那个节点,因为是优先队列,所以距离最小的那个潜力最大
            State *cur = pq.top();
            pq.pop();
            int curId = cur->id;
            int distFromStart = cur->distFromStart;
            if(distFromStart > distTo[curId]){
                continue; // 已经有更近的路径到达了当前节点
            }
            for(int nodeId: graph[curId]){
                int nextDist = distTo[curId] + weight[make_pair(curId, nodeId)];
                if(nextDist < distTo[nodeId]){
                    distTo[nodeId] = nextDist;
                    State *tmp = new State(nodeId, nextDist);
                    pq.push(tmp);
                }
            }
        } // while
        return distTo;
    }
};

vector<int> dijsktraV2(vector<vector<int>> &nums, int start, int end, int n){
    // build graph
    vector<vector<int>> graph(n+1, vector<int>());
    vector<pair<int,int>> weight;  // 记录weight
    for(auto num: nums){
        graph[num[0]].push_back(num[1]);
        weight[make_pair(num[0], num[1])] = num[2];
    }

    // bfs
    priority_queue<Mem*, vector<Mem*>, cmp> pq;
    pq.push(new Mem(start, 0));

    vector<int> distTo(n+1, INT_MAX);
    distTo[start] = 0;

    while(!pq.empty()){
        Mem *curNode = pq.top();  // 每次找到优先队列中最短的节点
        pq.pop();
        int curId = curNode->id;
        int curNodeDist = curNode->dist;
        // 到达了目的节点,由于是优先队列中弹出的,所以第一次遇见的时候就是最短的
        if(curId == end){
            return curNodeDist;
        }

        //已经有了一条路径到了curId节点,那么解析
        if(curNodeDist > distTo[curId]){
            continue;
        }
        for(int nextNodeId: graph[curId]){
            int nextNodeDist = distTo[curId] + weight[make_pair(curId, nextNodeId)];
            if(nextNodeDist < distTo[nextNodeId]){
                distTo[nextNodeId] = nextNodeDist;
                pq.push(nextNodeId);
            }
        }
    }// while
    return -1;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值