(未整理完)十月每日一题打卡

news2024/7/4 4:20:58

在这里插入图片描述

每日打卡

10.1 [重新格式化电话号码 lc1694](1694. 重新格式化电话号码 - 力扣(LeetCode))

模拟题:特殊情况就是在最后划分完全部三个之后,还剩四个需要变成aa-bb

class Solution {
public:
    string reformatNumber(string number) {
        string ans;
        queue<char> q;
        for(char ch: number)
        {
            if(ch != ' ' && ch != '-')
                q.push(ch);
        }
        int cnt = 0;
        while(q.size())
        {
            if(cnt == 0 && q.size() == 4)
            {
                ans += q.front();
                q.pop();
                ans += q.front();
                q.pop();
                ans += '-';
                ans += q.front();
                q.pop();
                ans += q.front();
                q.pop();
            }
            if(!q.size())
                break;
            if(cnt == 3)
            {
                ans += '-';
                cnt = 0;
            }
            else
            {
                ans += q.front();
                q.pop();
                cnt++;
            }
        }
        return ans;
    }
};

10.2 [在LR字符串中交换相邻字符 lc 777](777. 在LR字符串中交换相邻字符 - 力扣(LeetCode))

在这里插入图片描述

题目的意思是L可以越过X向左移动,R可以越过X向右移动。

!也就是去掉X后start和end字符串的L和R位置相同!

class Solution {
public:
    bool canTransform(string start, string end) {
        int n = start.size();
        int i = 0, j = 0;
        while(1)
        {
            //越过所有的X
            while(i < n && start[i] == 'X')
                i++;
            while(j < n && end[j] == 'X')
                j++;
            //判断现在的i和j情况
            //如果两个都走到底了那可以
            if(i == n && j == n)
                return true;
            //有一个走到底了另一个没有或者二者对应的不相同那不行
            if(i == n || j == n || start[i] != end[j])
                return false;
            //两者的位置不同也不行L可以左移所以start的可以在end后面
            if(start[i] == 'L' && i < j)
                return false;
            //R可以右移所以start的可以在end前面
            if(start[i] =='R' && i > j)
                return false;
            i++;
            j++;
        }
        return true;
    }
};

10.2 [每日温度 lc739](739. 每日温度 - 力扣(LeetCode))

单调栈

在这里插入图片描述

明显的单调栈就是说维持这个栈单调递减,如果出现比栈顶大的元素,说明下一个更高温度已经出现,可以将其pop出来了。

可以在栈底设置一个哨兵0,这样便于处理边界

class Solution {
public:
    vector<int> dailyTemperatures(vector<int>& temp) {
        int n = temp.size();
        vector<int> ans(n, 0);
        stack<int> stk;
        stk.push(0);
        for(int i = 1; i < n; i++)
        {
            while(!stk.empty() && temp[stk.top()] < temp[i])
            {
                ans[stk.top()] = i - stk.top();
                stk.pop();
            }
            stk.push(i);
        }
        return ans;
    }
};

10.3 [检查二进制字符串字段 lc1784](1784. 检查二进制字符串字段 - 力扣(LeetCode))

在这里插入图片描述

题目含义很难理解,看了评论区之后:连续若干个"1"组成的字段是由一个或者多个连续‘1’组成的,如果这样的字段不超过1个,就返回true,多于1个就返回false。

1000 true 110001 false 统计即可

class Solution {
public:
    bool checkOnesSegment(string s) {
        int cnt = 0;
        int n = s.size();
        int len = 0;
        for(int i = 0; i < n; i++)
        {
            while(i < n && s[i] == '1')
            {
                len++;
                i++;
            }
            if(len >= 1)
                cnt++;
            if(i < n && s[i] == '0')
                len = 0;
            
        }
        return cnt <= 1;
    }
};

10.3 [柱状图中的最大矩形 lc 84](84. 柱状图中最大的矩形 - 力扣(LeetCode))

在这里插入图片描述

我们之前做过一个类似的,盛最多水的容器,那个是构造的矩形是两个边界中最小即可,也即是双指针就行。这个不一样的是你需要使用整个容器内的最矮的作为高。所以我们想遍历每个柱子,以其作为高h,然后去寻找最宽的边,也即是向两边分别找高于h的柱子,找到第一个低于h的就停止。

这个也是单调栈,对于单调递增的栈来说:栈里的前一个元素就是左边第一个小于该元素的值,右边第一个小于我们可以在比较中得到。当发现小于栈顶元素时就可以得到右边第一个了,否则就加入栈中即可。

class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        int n = heights.size() + 2;
        //向两边加一个哨兵
        heights.insert(heights.begin(), 0);
        heights.push_back(0);
        int ans = 0;
        stack<int> s;
        for(int i = 0; i < n; i++)
        {
            while(!s.empty() && heights[i] < heights[s.top()])
            {
                int j = s.top();
                s.pop();
                ans = max(ans, heights[j] * (i - s.top() - 1));
            }
            s.push(i);
        }
        return ans;
    }
};

10.3 [最大矩形 lc85](85. 最大矩形 - 力扣(LeetCode))

就是上面lc84的二维版本

最形象的图就是这个

只用第一行高度是 1 0 1 0 0

12行高度是 2 0 2 1 1

13行高度是 3 1 3 2 2

这几行分别调用lc84即可取最大即可!

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

class Solution {
public:
    int maximalRectangle(vector<vector<char>>& matrix) {
        int row = matrix.size(), col = matrix[0].size();
        if(row == 0 || col == 0)
            return 0;
        int ans = 0;
        vector<int> height(col, 0);
        for(int i = 0; i < row; i++)
        {
            for(int j = 0; j < col; j++)
            {
                if(matrix[i][j] == '1')
                    height[j] =  height[j] + 1;
                else
                    height[j] = 0;
            }
            for(int x: height)
                cout << x << " ";
            cout << endl;
            ans = max(ans, largestRectangleArea(height));
        }
        return ans;
    }

    int largestRectangleArea(vector<int> heights) {
        int n = heights.size() + 2;
        heights.insert(heights.begin(), 0);
        heights.push_back(0);
        int ans = 0;
        stack<int> s;
        for(int i = 0; i < n; i++)
        {
            while(!s.empty() && heights[i] < heights[s.top()])
            {
                int j = s.top();
                s.pop();
                ans = max(ans, heights[j] * (i - s.top() - 1));
            }
            s.push(i);
        }
        return ans;
    }
};

10.4 [使括号有效的最少添加 lc 921](921. 使括号有效的最少添加 - 力扣(LeetCode))

这个就是有效的括号,但是由于是任意位置插入左括号和右括号都行,只需要数量对应上即可。左括号+1,右括号先抵消再计数即可
在这里插入图片描述

class Solution {
public:
    int minAddToMakeValid(string s) {
        int l = 0, cnt = 0;
        for(char ch: s)
        {
            if(ch == '(')
                l++;
            else if(l > 0 && ch == ')')
                l--;
            else if(l == 0 && ch == ')')
                cnt++;
        }
        return cnt + l;
    }
};

10.4 [最短无序连续子数组 lc 581] (581. 最短无序连续子数组 - 力扣(LeetCode))

在这里插入图片描述

这个看起来很简单,本来想着从两边向中间扩展出现无序就停止来着,但是其中的等号很麻烦。这个题一点都不简单。

两个边界l, r。l是最左边需要开始排序的数,应该从右边开始遍历。如果不需要排序的话,那么从右边开始应该每一个数nums[j]都小于等于右边遍历过的min。反之若nums[j] > min的话,就需要记录下来需要排序的值l。

同理,r是最右边需要开始排序的数,应该从左边开始遍历。如果不需要排序的话,那么从左边开始应该每一个数nums[i]都大于等于左边遍历过前i - 1个数的max。反之若nums[j] < max的话,就需要记录下来需要排序的值r。

class Solution {
public:
    int findUnsortedSubarray(vector<int>& nums) {
        int n = nums.size();
        int ma = INT_MIN, mi = INT_MAX;
        int l = 0, r = 0;
        for(int i = 0; i < n; i++)
        {
            if(nums[i] < ma)
                r = i;
            else
                ma = max(ma, nums[i]);
        }
        for(int j = n - 1; j >= 0; j--)
        {
            if(nums[j] > mi)
                l = j;
            else
                mi = min(mi, nums[j]);
        } 
        if(l == r)
            return 0;
        else
            return r - l + 1;
    }
};

10.5 [子域名访问计数 lc 811](811. 子域名访问计数 - 力扣(LeetCode))

在这里插入图片描述

简单模拟:使用hashmap的key存储域名,value存储个数,处理字符串计数即可。

class Solution {
public:
    vector<string> subdomainVisits(vector<string>& cpdomains) {
        unordered_map<string, int> hashMap;
        vector<string> ans;
        for(string s: cpdomains)
        {
            int i = 0;
            while(i < s.size() && s[i] != ' ')
                i++;
            int cnt = atoi(s.substr(0, i).c_str());
            string s1 = s.substr(++i);  //google.mail.com
            if(hashMap.find(s1) != hashMap.end())
                hashMap[s1] += cnt;
            else
                hashMap[s1] = cnt;
            while(i < s.size() && s[i] != '.')
                i++;
            string s2 = s.substr(++i); //mail.com
            if(hashMap.find(s2) != hashMap.end())
                hashMap[s2] += cnt;
            else
                hashMap[s2] = cnt;
            while(i < s.size() && s[i] != '.')
                i++;
            if(i < s.size() && s[i] == '.')
            {
                string s3 = s.substr(++i); //com
                if(hashMap.find(s3) != hashMap.end())
                    hashMap[s3] += cnt;
                else
                    hashMap[s3] = cnt;
            }
        }
        for(auto x: hashMap)
        {
            string s = to_string(x.second) + " " + x.first;
            ans.push_back(s);
        }
        return ans;
    }
};

[10.5 盛最多水的容器 lc 11](11. 盛最多水的容器 - 力扣(LeetCode))

这个就很简单啦,双指针遍历一下

class Solution {
public:
    int maxArea(vector<int>& height) {
        int n = height.size();
        int i = 0, j = n - 1;
        int ans = 0;
        while(i < j)
        {
            int s = min(height[i], height[j]) * (j - i);
            ans = max(ans, s);
            if(height[i] < height[j])
                i++;
            else
                j--;
        }
        return ans;
    }
};

[10.5 删掉链表的倒数第n个节点 lc 19](19. 删除链表的倒数第 N 个结点 - 力扣(LeetCode))

也很简单啦,就是快慢指针先找到倒数第n个节点,然后删除即可。

注意一些边界条件,比如删除头节点、删除只有一个元素的链表等

/**
 * 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* removeNthFromEnd(ListNode* head, int n) {
        ListNode* p = head;
        if(head->next == nullptr)
            return nullptr;
        for(int i = 0; i < n; i++)
            p = p->next;
        ListNode* q = head;
        if(p == nullptr)
            return head->next;  //删掉头节点

        while(p->next != nullptr)
        {
            p = p->next;
            q = q->next;
        }
        ListNode* nx = q->next;
        q->next = nx->next; 
        return head;
    }
};

[10.6 三等分 lc 927](927. 三等分 - 力扣(LeetCode))

三个指针判断三部分是否相等,二进制是否相等首先看1的个数,其次看第一个1后的排列是否相等。`

class Solution {
public:
    vector<int> threeEqualParts(vector<int>& arr) {
        vector<int> ans = {-1, -1};
        int n = arr.size();
        int cnt = 0;
        //求出所有1的数量
        for(int i = 0; i < n; i++)
            cnt += arr[i];
        if(cnt == 0)
            return {0, n - 1};
        //三者平分 能分继续 不能分就不行
        if(cnt % 3) return ans;
        cnt = cnt / 3;
        int i = 0, j = 0, k = 0, s = 0;
        //根据1的数量将三个指针定位到各自第一个1的位置
        while(i < n && s < 1) { s += arr[i++];}
        s = 0;
        while(j < n && s < cnt + 1)  { s += arr[j++];}
        s = 0;
        while(k < n && s < 2 * cnt + 1)  { s += arr[k++];}

        //开始判断第一个1后面的是否完全相同
        while(k < n && arr[i] == arr[j] && arr[j] == arr[k])
        {
            i++; j++; k++;
        }
        if(k < n)
            return ans;
        else
            return {i - 1, j};

    }
};

[10.6 下一个排列 lc 31](31. 下一个排列 - 力扣(LeetCode))

这个题挺巧妙的,需要仔细分析排列。我们以2 6 3 5 4 1为例,可以从右边开始分析。就是如果是降序比如5 4 1这样的,就是已经是最大的了,不会再有下一个排列了。所以我们第一步需要从右边找第一个升序的,找到了 3 5。为了是下一个排列因此我们需要使这个排列尽可能地小,所以我们从后面5 4 1中选一个第一个比3大地和他交换,得到一个比3大一点的新开头,2 6 4 5 3 1。接下来需要将后面的变成最小的,因为是逆序,所以直接反转即可。

class Solution {
public:
    void nextPermutation(vector<int>& nums) {
        int n = nums.size();
        int i = n - 1;
        //找到第一个升序的 3 5 
        while(i > 0 && nums[i] <= nums[i - 1]) i--;
        //如果不存在升序说明全部倒序,直接全部逆序即可
        if(i <= 0) {reverse(nums.begin(), nums.end()); return;}
        int j = i - 1; // j是3 等着待交换的那个
        //向右边倒序序列中找比nums[j]大一点的值 i - 1就是那个4
        while(i < n && nums[i] > nums[j]) i++;
        cout << nums[j] << " " << nums[i - 1] << endl;
        //swap(nums[j], nums[i - 1]); 将二者交换
        int t = nums[j];
        nums[j] = nums[i - 1];
        nums[i - 1] = t;
        //最后将后面的倒序逆转变小一点的排列
        reverse(nums.begin() + j + 1, nums.end());
    }
};

[10.7 最大升序子序列和 lc1800](1800. 最大升序子数组和 - 力扣(LeetCode))

class Solution {
public:
    int maxAscendingSum(vector<int>& nums) {
        int ans = nums[0], s = nums[0];
        for(int i = 1; i < nums.size(); i++)
        {
            if(nums[i - 1] < nums[i])
                s += nums[i];
            else
                s = nums[i];
            ans = max(ans, s);
        }
        return ans;
    }
};

[10.7 寻找重复数 lc 287](287. 寻找重复数 - 力扣(LeetCode))

快慢指针,将1,3,4,2,2看成链表,判断链表是否有环以及找到链表的入口。

在这里插入图片描述

class Solution {
public:
    int findDuplicate(vector<int>& nums) {
        //将数组看成链表,找到环的入口
        int slow = 0, fast = 0;
        while(1)
        {
            slow = nums[slow];
            fast = nums[nums[fast]];
            if(slow == fast)
                break;
        }
        fast = 0;
        while(slow != fast)
        {
            slow = nums[slow];
            fast = nums[fast];
        }
        return slow;
    }
};

[10.7 找到数组中消失的数字 lc 448](448. 找到所有数组中消失的数字 - 力扣(LeetCode))

这个题也是将数组中的值和下标映射起来,比如[4,3,2,7,8,2,3,1],nums[0] = 4,则将4对应的nums[4] = 8换成-8代表有4了,重复的已经成为负数的就不变,最后值为正的下标就是消失的数字。

class Solution {
public:
    vector<int> findDisappearedNumbers(vector<int>& nums) {
        vector<int> ans;
        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)
                ans.push_back(i + 1);
        }
        return ans;
    }
};

[10.8 优势洗牌 lc 870](870. 优势洗牌 - 力扣(LeetCode))

贪心之田忌赛马:在nums1中找大于nums2[i]的最小值,如果没有则返回nums1中的最小值。直接找会导致超时,二分查找第一个。

class Solution {
public:
    vector<int> advantageCount(vector<int>& nums1, vector<int>& nums2) {
        int n = nums1.size();
        vector<int> ans(n, 0);
        bool st[n];
        int idx = 0;
        memset(st, false, sizeof st);
        sort(nums1.begin(), nums1.end());
        for(int i = 0; i < n; i++)
        {
            int l = 0, r = n;
            while(l < r)
            {
                int mid = l + r >> 1;
                if(nums1[mid] > nums2[i])
                    r = mid;
                else
                    l = mid + 1;
            }
            while(l < n && (st[l] || nums1[l] == nums2[i]))
                l++;
            if(l < n)
            {
                ans[i] = nums1[l];
                st[l] = true;
            }
            else
            {
                while(st[idx]) idx++;
                ans[i] = nums1[idx];
                st[idx++] = true;
            }
       }
        return ans; 
    }
};

!10.8 三数之和 lc 15

[10.10 数组中第k个元素](215. 数组中的第K个最大元素 - 力扣(LeetCode))

1. 快速排序

快速排序每次都可以使nums[r]== x,然后左侧都小于等于x,右侧都大于等于x。因此只要某次确定值的下标是k就可以返回第k个最大的元素了。

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        return quicksort(nums, k, 0, nums.size() - 1);
    }

    int quicksort(vector<int>& nums, int k, int left, int right)
    {
        if(right < left)
            return INT_MAX;
        int x = nums[(left + right) >> 1];
        int l = left - 1, r = right + 1;
        while(l < r)
        {
            do l++; while(nums[l] > x);
            do r--; while(nums[r] < x);
            if(l < r)
            {
                int t = nums[l]; nums[l] = nums[r]; nums[r] = t;
            }
        }
        int p;
        if(nums[l] == x)
            p = l;
        if(nums[r] == x)
            p = r;
        if(p == k - 1)
            return nums[p];
        else if(p > k - 1)
            return quicksort(nums, k, left, r);
        else
            return quicksort(nums, k, r + 1, right);
        
    }
};

2. 建堆

维护一个k长度的小顶堆,堆顶元素就是第k大,当堆顶元素不再是第k大的时候,就调整堆。

最小堆 - 数组中的第K个最大元素 - 力扣(LeetCode)

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        int n = nums.size();

        make_heap(nums, k);
        for(int i = k; i < n; i++)
        {
            if(nums[i] < nums[0])
                continue;
            else
            {
                nums[0] = nums[i];
                shift_down(nums, k, 0);
            }
        }
        return nums[0];
    }

    void shift_down(vector<int>& nums, int k, int i)
    {
        int j = 2 * i + 1;
        while(j < k)
        {
            if(j + 1 < k && nums[j] > nums[j + 1]) j++;
            if(nums[i] > nums[j])
            {
                swap(nums[i], nums[j]);
                i = j;
                j = 2 * i + 1;
            }
            else
                break;
        }
    }
    void make_heap(vector<int>& nums, int k)
    {
        for(int i = k / 2; i >= 0; i--)
            shift_down(nums, k, i);
    }
};

10.10 使序列递增的最小交换次数 lc 801

状态机dp:dp[i] [0]表示第i位不发生交换使得前i位递增的最小交换次数,1同理。

有两种情况可以交换:

  • 两组都满足前后大于,这种就是要不i和i-1都不交换,要么都交换。
  • 交叉满足前后大小关系,这种要不i- 1交换要不i交换。
class Solution {
public:
    int minSwap(vector<int>& nums1, vector<int>& nums2) {
        int n = nums1.size();
        int dp[n][2];
        memset(dp, 0x3f, sizeof dp);
        dp[0][0] = 0;
        dp[0][1] = 1;
        for(int i = 1; i < n; i++)
        {
            if(nums1[i] > nums1[i - 1] && nums2[i] > nums2[i - 1])
            {
                dp[i][0] = dp[i - 1][0];  //要么不交换
                dp[i][1] = dp[i - 1][1] + 1; //要么两个都交换
            }
            if(nums1[i] > nums2[i - 1] && nums2[i] > nums1[i - 1])
            {
                dp[i][0] = min(dp[i][0], dp[i - 1][1]);  //前一个发生交换
                dp[i][1] = min(dp[i][1], dp[i - 1][0] + 1); //后面这个发生交换
            }
        }
        return min(dp[n - 1][0], dp[n - 1][1]);
    }
};

10.11 仅执行一次字符串交换能否使两个字符串相等 lc 1790

记录下两个不同的下标,超过两个不同返回false,最后看不同的两个下标交换后是否相同。

class Solution {
public:
    bool areAlmostEqual(string s1, string s2) {
        int n = s1.size();
        int cnt = 0;
        int a[2];
        for(int i = 0; i < n; i++)
        {
            if(s1[i] != s2[i])
            {
                if(cnt == 2)
                {
                    cnt++;
                    break;
                }
                a[cnt++] = i;
            }
        }
        if(cnt == 1 || cnt > 2)
            return false;
        if(cnt == 0)
            return true;
        if(s1[a[0]] == s2[a[1]] && s1[a[1]] == s2[a[0]])
            return true;
        return false;
    }
};

10.12 链表组件 lc 817

模拟即可

/**
 * 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:
// 被骗了,是求所有组件的个数而不是求组件的最大长度无语无语
    int numComponents(ListNode* head, vector<int>& nums) {
        int n = nums.size(), ans = 0;
        unordered_set<int> hashset;
        for(int x: nums)
            hashset.insert(x);
        ListNode* p = head;
        int cnt = 0;
        while(p != nullptr)
        {
            if(hashset.find(p->val) != hashset.end())
                cnt++;
            else
            {
                if(cnt)
                    ans++;
                cnt = 0;
                
            }
            p = p->next;
        }
        if(cnt)
            ans++;
        return ans;
    }
};

10.12 接雨水 lc 42

接雨水的关键就是单调栈

不同于柱状图的最大矩形(向两边找低于栈顶的递增),接雨水需要向两边找高于栈顶的,这样才能接住雨水,因此是递减栈。

以栈顶元素作为雨水高度t = height[stk.top()],当右边高于栈顶时,就是找到了右边高于的,然后去找左边高于的,也即是下一个栈顶。还有要是有和栈顶相同的也要pop出去,而且高度要减去。下一个栈顶就是左边高于栈顶的了height[stk.top()]。比较这两边高的选小的作为高,减去t,乘上宽度即可。

在这里插入图片描述

class Solution {
public:
    int trap(vector<int>& height) {
        int n = height.size();
        int ans = 0;
        stack<int> stk;
        for(int i = 0; i < n; i++)
        {
            while(!stk.empty() && height[i] > height[stk.top()])
            {
                int t = stk.top();
                stk.pop();
                while(!stk.empty() && height[stk.top()] == height[t])
                    stk.pop();
                if(!stk.empty())
                    ans += ( min(height[stk.top()], height[i]) - height[t] ) * (i - stk.top() - 1);
            }
            stk.push(i);
        }
        return ans;
    }
};

10.13 合并K个升序链表 lc 23

两两归并,最后变成两个合并。

/**
 * 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* mergeTwoLists(ListNode* l1, ListNode* l2)
    {
        ListNode* dummy = new ListNode(-1);
        ListNode* p = dummy;
        if(l1 == nullptr && l2 == nullptr)
            return nullptr;
        while(l1 != nullptr && l2 != nullptr)
        {
            if(l1->val < l2->val)
            {
                p->next = l1;
                l1 = l1->next;
            }
            else
            {
                p->next = l2;
                l2 = l2->next;
            }
            p = p->next;
        }
        while(l1 != nullptr)
        {
            p->next = l1;
            l1 = l1->next;
            p = p->next;
        }
        while(l2 != nullptr)
        {
            p->next = l2;
            l2 = l2->next;
            p = p->next;
        }
        return dummy->next;
    }
    ListNode* binaryMerge(vector<ListNode*>& lists, int low, int high)
    {
        if(low > high)
            return nullptr;
        if(low == high)
            return lists[low];
        if(high - low == 1)
            return mergeTwoLists(lists[low], lists[high]);
        int mid = (low + high) >> 1;
        return mergeTwoLists(binaryMerge(lists, low, mid), binaryMerge(lists, mid + 1, high));
    }
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        return binaryMerge(lists, 0, lists.size() - 1);
    }
};

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

在这里插入图片描述

滑动窗口

class Solution {
public:
    vector<int> findAnagrams(string s, string p) {
        vector<int> ans;
        int sn = s.size();
        int pn = p.size();
        if(pn > sn) return {};
        int cnts[26];
        int cntp[26];
        memset(cnts, 0, sizeof cnts);
        memset(cntp, 0, sizeof cntp);
        for(int i = 0; i < pn; i++)
            cntp[p[i] - 'a']++;
        int i = 0, j = 0;
        for(; j < pn; j++)
            cnts[s[j] - 'a']++;
        while(j < sn)
        {
            bool f = true;
            for(int k = 0; k < 26; k++)
            {
                if(cnts[k] != cntp[k])
                    f = false;
            }
            if(f)
                ans.push_back(i);
            cnts[s[i++] - 'a']--;
            if(j < sn)
                cnts[s[j++] - 'a']++;  
        }
        bool f = true;
        for(int k = 0; k < 26; k++)
        {
            if(cnts[k] != cntp[k])
                f = false;
        }
        if(f)
            ans.push_back(i);
        return ans;
    }
};

10.13 最多能完成排序的块 lc 769

规律:区间数的最大值小于等于下标就可以分块

class Solution {
public:
    int maxChunksToSorted(vector<int>& arr) {
        //区间的最大值小于等于索引则可以划分区间
        int n = arr.size();
        int ans = 0, ma = 0;
        for(int i = 0; i < n; i++)
        {
            if(arr[i] > ma)
                ma = arr[i];
            if(ma <= i)
            {
                ans++;
                ma = 0;
            }
        }
        return ans;
    }
};

!10.14 不同的子序列 lc940

10.14 路径总和 I lc 112

我一开始写的是,先不管下面这个空树是否为空。看[1, 2] 1 这个例子,就是这棵树只有1 ,2 一侧两个节点。在我的判断中走到1这个节点就可以判断true了。但是题目要求的是到叶子节点,所以判断条件要加上节点的左右节点都为空。

//wrong
class Solution {
public:
    bool hasPathSum(TreeNode* root, int targetSum) {
        if(root == nullptr && targetsum == 0)
            return true;
        if(root == nullptr)
            return false;
        return hasPathSum(root->left, targetSum - root->val) || hasPathSum(root->right, targetSum - root->val);
    }
};
//right
class Solution {
public:
    bool hasPathSum(TreeNode* root, int targetSum) {
        if(root == nullptr)
            return false;
        if(targetSum == root->val && root->left == nullptr && root->right == nullptr)
            return true;
        return hasPathSum(root->left, targetSum - root->val) || hasPathSum(root->right, targetSum - root->val);
    }
};

10.14 路径总和II lc 113

在1的基础上要记录下满足要求的路径和

class Solution {
public:
    vector<vector<int>> ans;
    vector<int> tmp;
    vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
        if(root == nullptr)
            return {};
        helper(root, targetSum);
        return ans;
    }
    void helper(TreeNode* root, int targetSum)
    {
        if(root == nullptr)
            return;
        if(targetSum == root->val && !root->left && !root->right)
        {
            tmp.push_back(root->val);
            ans.push_back(tmp);
            tmp.pop_back();
            return ;
        }
        tmp.push_back(root->val);
        helper(root->left, targetSum - root->val);
        helper(root->right, targetSum - root->val);
        tmp.pop_back();
    }
};

10.14 路径总和III lc 437

路径不需要从父节点开始,也不需要在叶子节点结束,但方向要向下。

两个dfs,第一个dfs遍历每个节点,第二dfs去计算和是否满足。

class Solution {
public:
    long long  ans = 0;
    int ts;
    int pathSum(TreeNode* root, int targetSum) {
        if(root == nullptr)
            return 0;
        ts = targetSum;
        dfs1(root);
        return ans;
    }
    void dfs1(TreeNode* root)
    {
        if(root == nullptr)
            return;
        dfs2(root, 0);
        dfs1(root->left);
        dfs1(root->right);
    }
    void dfs2(TreeNode* root, long long curSum)
    {
        if(root == nullptr)
            return;
        curSum += root->val;

        if(curSum == ts)
            ans++;
        
        dfs2(root->left, curSum);
        dfs2(root->right, curSum);
    }
};

树上的前缀和:哇塞!最完整的路径是从根节点到叶子节点,这题相当于在这些路径上找区间和=targetsum的,那不就是前缀和吗!

curSum - preSum = targetSum即可。

class Solution {
public:
    unordered_map<long long, int> preSum;
    int targetSum;
    int ans = 0;
    int pathSum(TreeNode* root, int ts) {
        if(root == nullptr)
            return 0;
        targetSum = ts;
        preSum[0] = 1;
        dfs(root, 0);
        return ans;
    }
    void dfs(TreeNode* root, long long curSum)
    {
        if(root == nullptr)
            return;
        curSum += root->val;
        if(preSum.find(curSum - targetSum) != preSum.end())
        {
            ans += preSum[curSum - targetSum];
        }
        preSum[curSum]++;
        dfs(root->left, curSum);
        dfs(root->right, curSum);
        preSum[curSum]--;
    }
};

10.14 二叉树的序列化与反序列化 lc 297

这道题主要是区分每个节点的值和null处理、负值处理的问题,其他就是递归即可

BFS

class Codec {
public:
    const int nll = 2000;
    // Encodes a tree to a single string.
    string serialize(TreeNode* root) {
        if(root == nullptr)
            return "";
        string data;
        queue<TreeNode*> q;
        q.push(root);
        while(q.size())
        {
            TreeNode* tmp = q.front();
            q.pop();
            if(tmp == nullptr)
            {
                data += "_#";
                continue;
            }
            data += "_" + to_string(tmp->val);
            q.push(tmp->left);
            q.push(tmp->right);
        }
        cout << data << endl;
        return data;
    }

    // Decodes your encoded data to tree.
    TreeNode* deserialize(string data) {
        if(data.size() == 0)
            return nullptr;
        vector<int> v;
        int i = 0;
        while(i < data.size())
        {
            int j = i + 1;
            while(j < data.size() && data[j] != '_')
                j++;
            string s = data.substr(i + 1, j - i - 1);
            cout << s << endl;
            if(s == "#")
                v.push_back(nll);
            else
                v.push_back(atoi(s.c_str()));
            i = j;
        }
        i = 0;
        TreeNode* root = new TreeNode(v[i++]);
        queue<TreeNode*> q;
        q.push(root);
        while(q.size())
        {
            TreeNode* tmp = q.front();
            q.pop();
            if(v[i] == nll)
                tmp->left = nullptr;
            else
            {
                tmp->left = new TreeNode(v[i]);
                q.push(tmp->left);
            }
            i++;
            if(v[i] == nll)
                tmp->right = nullptr;
            else
            {
                tmp->right = new TreeNode(v[i]);
                q.push(tmp->right);
            }
            i++;
        }
        return root;
    }
};

DFS

class Codec {
public:
    const int nll = 2000;
    vector<int> v;
    int i = 1;
    // Encodes a tree to a single string.
    string serialize(TreeNode* root) {
        if(root == nullptr)
            return "_#";
        return "_" + to_string(root->val) +  serialize(root->left) + serialize(root->right);
    }
    void helper(string data)
    {
        int i = 0;
        while(i < data.size())
        {
            int j = i + 1;
            while(j < data.size() && data[j] != '_')
                j++;
            string s = data.substr(i + 1, j - i - 1);
            cout << s << endl;
            if(s == "#")
                v.push_back(nll);
            else
                v.push_back(atoi(s.c_str()));
            i = j;
        }
    }
    TreeNode* build(TreeNode* root)
    {
        if(v[i] == nll)
        {
            root->left = nullptr;
            i++;
        }
        else
        {
            root->left = new TreeNode(v[i]);
            i++;
            build(root->left);
        }
        if(v[i] == nll)
        {
            root->right = nullptr;
            i++;
        }
        else
        {
            root->right = new TreeNode(v[i]);
            i++;
            build(root->right);
        }
        return root;
    }
    // Decodes your encoded data to tree.
    TreeNode* deserialize(string data) {
        if(data == "_#")
            return nullptr;
        helper(data);
        TreeNode* root = new TreeNode(v[0]);
        return build(root);
    }
};

10.15 目标和 lc494

1.简单dfs

class Solution {
public:
    int n;
    //int ans = 0;
    int findTargetSumWays(vector<int>& nums, int target) {
        n = nums.size();
        return dfs(nums, target, 0, 0);
    }
    int dfs(vector<int>& nums, int target, int curSum, int i)
    {
        if(i == n && curSum == target)
            return 1;
        if(i == n)
            return 0;
        int n1 = dfs(nums, target, curSum + nums[i], i + 1);
        int n2 = dfs(nums, target, curSum - nums[i], i + 1);
        return n1 + n2;
    }
};

2. dfs+记忆化搜索

memo记录的是key = (i, cursum), value=要求的个数

class Solution {
public:
    int n;
    //int ans = 0;
    unordered_map<string, int> memo;
    int findTargetSumWays(vector<int>& nums, int target) {
        n = nums.size();
        return dfs(nums, target, 0, 0);
    }
    int dfs(vector<int>& nums, int target, int curSum, int i)
    {
        string key = to_string(i) + "_" + to_string(curSum);
        if(memo.count(key))
            return memo[key];
        if(i == n && curSum == target)
        {
            memo[key]++;
            return memo[key];
        }
        if(i == n)
        {
            memo[key] = 0;
            return memo[key];
        }
        int n1 = dfs(nums, target, curSum + nums[i], i + 1);
        int n2 = dfs(nums, target, curSum - nums[i], i + 1);
        memo[key] = n1 + n2;
        return n1 + n2;
    }
};

3. 01背包

在记忆化的基础上变成01背包

class Solution {
public:
    int findTargetSumWays(vector<int>& nums, int target) {
        int n = nums.size();
        int sum = 0;
        for(int x: nums)
            sum += x;
        if(target > sum || target < -sum) return 0;
        vector<vector<int>> dp(n + 1, vector<int>(2 * sum + 1, 0));
        dp[0][0 + sum] = 1;
        for(int i = 1; i <= n; i++)
        {
            for(int cur = -sum; cur <= sum; cur++)
            {
                if(cur - nums[i - 1] >= -sum)
                    dp[i][cur + sum] = dp[i - 1][cur - nums[i - 1] + sum];
                if(cur + nums[i - 1] <= sum)
                    dp[i][cur + sum] += dp[i - 1][cur + nums[i - 1] + sum];
            }
        }
        return dp[n][target + sum];
    }
};

10.15 分割等和子集 lc 416

划分两个子集使得x = y,也即是找到一个子集使得x=sum/2。也就是从这些数字中选一些数使得和为sum/2。

01背包问题

class Solution {
public:
    int n;
    bool canPartition(vector<int>& nums) {
        n = nums.size();
        int sum = 0;
        for(int x: nums)
            sum += x;
        if(sum % 2) return false;
        else return findTargetSumWays(nums, sum / 2);
    }
    int findTargetSumWays(vector<int>& nums, int target)
    {
        vector<vector<bool>> dp(n + 1, vector<bool>(target + 1, false));
        for(int i = 0; i <= n; i++)
            dp[i][0] = true;
        for(int i = 1; i <= n; i++)
        {
            for(int cur = 0; cur <= target; cur++)
            {
                dp[i][cur] = dp[i - 1][cur];
                if(nums[i - 1] <= cur)
                    dp[i][cur] = dp[i][cur] || dp[i - 1][cur - nums[i - 1]];
            }
        }
        return dp[n][target];
    }
};

在这里插入图片描述

!10.15 用栈操作构建数组 lc 1441

!10.16 可能的二分法 lc 886

10.17 完全平方数

还是01背包问题,就是从平方和中选选到和为target的最小数量

class Solution {
public:
    const int INF = 0x3f3f3f3f;
    int numSquares(int n) {
        vector<int> sq;
        for(int i = 0; i * i <= n; i++)
            sq.push_back(i * i);
        int dp[n + 1];
        memset(dp, INF, sizeof dp);
        dp[1] = 1;
        dp[0] = 0; 
        for(int i = 0; i < sq.size(); i++)
        {
            for(int j = 0; j <= n; j++)
            {
                if(sq[i] <= j)
                    dp[j] = min(dp[j], dp[j - sq[i]] + 1);
            }
        }
        return dp[n];
    }
};

10.17 零钱兑换 lc 322

完全背包问题:物品可以无限使用,要求背包装满,要求使用的数量最少。

在满足:amount=v1x1+v2x2+v3x3+…+vnxn 的条件下,求: target=min{x1+x2+x3+…xn}可以dfs将所有的组合拿出来,然后取硬币数最小。

dp[i]表示硬币和为i时的最小硬币数,然后看取不取前i个硬币,取最小即可。

class Solution {
public:
    const int INF = 0x3f3f3f3f;
    int coinChange(vector<int>& coins, int amount) {
        int n = coins.size();
        int dp[amount + 1];
        memset(dp, INF, sizeof dp);
        dp[0] = 0;
        for(int i = 0; i < n; i++)
        {
            for(int j = 0; j <= amount; j++)
            {
                if(coins[i] <= j)
                {
                    dp[j] = min(dp[j], dp[j - coins[i]] + 1);
                }
            }
        }
        if(dp[amount] == INF)
            return -1;
        else
            return dp[amount];
    }
};

!10.17 水果成篮 lc 904

!10.18 最大为 N 的数字组合 lc 902

10.18 环形链表 lc 141

快慢指针

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    bool hasCycle(ListNode *head) {
        if(head == nullptr)
            return false;
        if(head->next == nullptr)
            return false;
        ListNode* fast = head;
        ListNode* slow = head;
        while(fast != nullptr)
        {
            slow = slow->next;
            fast = fast->next;
            if(fast != nullptr)
                fast = fast->next;
            if(slow == fast)
                return true;
        }
        return false;
    }
};

10.18 环形链表|| lc 142

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode* fast = head, *slow = head;
        if(head == nullptr) return nullptr;
        if(head->next == nullptr) return nullptr;
        while(fast != nullptr)
        {
            slow = slow->next;
            fast = fast->next;
            if(fast != nullptr)
                fast = fast->next;
            if(fast == slow)
            {
                fast = head;
                while(fast != slow)
                {
                    fast = fast->next;
                    slow = slow->next;
                }
                return fast;
            }
        }
        return nullptr;
    }
};

10.18 删除链表的倒数第 N 个结点 lc 19

还是快慢指针找到倒数第n个节点然后再删除~下次再练习

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* p = head;
        if(head->next == nullptr)
            return nullptr;
        for(int i = 0; i < n; i++)
            p = p->next;
        ListNode* q = head;
        if(p == nullptr)
            return head->next;  //删掉头节点

        while(p->next != nullptr)
        {
            p = p->next;
            q = q->next;
        }
        ListNode* nx = q->next;
        q->next = nx->next; 
        return head;
    }
};

!10.19 无法吃午餐肉的同学 lc 1700

!10.19 括号的生成 lc 22

!10.19 组合总和 lc 39

回溯

class Solution {
public:
    vector<vector<int>> ans;
    vector<int> tmp;
    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
        sort(candidates.begin(), candidates.end());
        dfs(candidates, target, 0, 0);
        return ans;
    }
    void dfs(vector<int>& candidates, int target, int curSum, int i)
    {
        if(curSum == target)
        {
            ans.push_back(tmp);
            return;
        }
        if(curSum > target)
        {
            return;
        }
        for(int j = i; j < candidates.size(); j++)
        {
            tmp.push_back(candidates[j]);
            dfs(candidates, target, curSum + candidates[j], j);
            tmp.pop_back();
        }
    }
};

!10.19 组合总数 II lc 42

class Solution {
public:
    vector<vector<int>> ans;
    vector<int> tmp;
    vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
        sort(candidates.begin(), candidates.end());
        dfs(candidates, target, 0, 0);
        return ans;
    }
    void dfs(vector<int>& candidates, int target, int cur, int last)
    {
        if(cur == target)
        {
            ans.push_back(tmp);
            return;
        }
        if(cur > target)
        {
            return;
        }
        for(int i = last; i < candidates.size(); i++)
        {
            if(i > last && candidates[i] == candidates[i - 1])
                continue;
            tmp.push_back(candidates[i]);
            dfs(candidates, target, cur + candidates[i], i + 1);
            tmp.pop_back();
        }

    }
};

!10.19 电话号码的字母组合 lc 17

10.20 缺失的第一个正数 lc 41

最大的缺失的正数也不会超过nums.size()。还是和下标相关

把每个数放在下标应该在的数上,然后从0开始判断如果和下标不一样的第一个数就是缺失的第一个正数。

class Solution {
public:
    int firstMissingPositive(vector<int>& nums) {
        int n = nums.size();
        for(int i = 0; i < n; i++)
        {
            while(nums[i] > 0 && nums[i] < n && nums[i] != nums[nums[i] - 1])
                swap(nums[i], nums[nums[i] - 1]);
        }
        for(int i = 0; i < n; i++)
        {
            if(nums[i] != i + 1)
                return i + 1;
        }
        return n + 1;
    }
};

10.20 寻找重复数 lc 287

把数组看成链表,找到环的入口

class Solution {
public:
    int findDuplicate(vector<int>& nums) {
        //将数组看成链表,找到环的入口
        int slow = 0, fast = 0;
        while(1)
        {
            slow = nums[slow];
            fast = nums[nums[fast]];
            if(slow == fast)
                break;
        }
        fast = 0;
        while(slow != fast)
        {
            slow = nums[slow];
            fast = nums[fast];
        }
        return slow;
    }
};

10.20 找到所有数组中消失的数字 lc 448

就是把出现的数字和下标关联起来,将出现的数字的下标存储的数变成负数,最后是正数的就是缺失的。

class Solution {
public:
    vector<int> findDisappearedNumbers(vector<int>& nums) {
        vector<int> ans;
        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)
                ans.push_back(i + 1);
        }
        return ans;
    }
};

!10.20 第K个语法符号lc 779

!10.21 股票价格跨度 lc 901

!10.22 根据身高重建队列 lc 406

!10.22 规划兼职工作lc 1235

!10.24 除自身以外的乘积 lc 238

!10.24 和为k的子数组 lc 560

!10.24 分割数组 lc 915

!10.25 最短的桥

!10.26 任务调度器 lc 621

!10.26 和至少为k的最短子数组 lc 862

!10.28 戳气球 lc 312

!10.28 子数组的最小值之和 lc 907

10.30 LRU缓存 lc 146

哈希表+ 双向链表:最关键的就是加上一个头节点和尾节点,剩下的就仔细写仔细调试就可以了。

struct Node
{
    int key;
    int value;
    Node* next;
    Node* pre;
    Node(int k, int v)
    {
        key = k;
        value = v;
        next = nullptr;
        pre = nullptr;
    }
};
class LRUCache {
public:
    Node* head;
    Node* nail;
    int cnt = 0;
    int cap;
    unordered_map<int, Node*> hashmap;
    LRUCache(int capacity) {
        cap = capacity;
        head = new Node(-1, -1);
        nail = new Node(-1, -1);
        head->next = nail;
        head->pre = nail;
        nail->next = head;
        nail->pre = head;
    }
    
    int get(int key) {
        if(hashmap.find(key) == hashmap.end())
            return -1;
        Node* tmp = hashmap[key];
        remove(tmp);
        addFromHead(tmp);
        return tmp->value;
    }
    void remove(Node* t)
    {
        hashmap.erase(t->key);
        Node* pt = t->pre;
        Node* nt = t->next;
        pt->next = nt;
        nt->pre = pt;
        cnt--;
    }
    void addFromHead(Node* t)
    {
        hashmap[t->key] = t;
        Node* nt = head->next;
        t->next = nt;
        t->pre = head;
        head->next = t;
        nt->pre = t;
        cnt++;
    }
    void put(int key, int value) {
        if(get(key) != -1)
        {
            head->next->value = value;
            return;
        }
        if(cnt < cap)
        {
            Node* tmp = new Node(key, value);
            addFromHead(tmp);
        }
        else
        {
            Node* tmp = new Node(key, value);
            Node* nt = nail->pre;
            remove(nt);
            addFromHead(tmp);
        }
    }
};

10.30 字母大小写全排列 lc 784

回溯

class Solution {
public:
    vector<string> ans;
    string tmp;
    vector<string> letterCasePermutation(string s) {
        dfs(s, 0);
        return ans;
    }
    void dfs(string s, int i)
    {
        if(i == s.size())
        {
            ans.push_back(tmp);
            return;
        }
        if(s[i] >= '0' && s[i] <= '9')
        {
            tmp += s[i];
            dfs(s, i + 1);
            tmp.pop_back();
        }
        else if(s[i] >= 'a' && s[i] <= 'z')
        {
            tmp += s[i];
            dfs(s, i + 1);
            tmp.pop_back();
            tmp += (s[i] - 32);
            dfs(s, i + 1);
            tmp.pop_back();
        }
        else
        {
            tmp += s[i];
            dfs(s, i + 1);
            tmp.pop_back();
            tmp += (s[i] + 32);
            dfs(s, i + 1);
            tmp.pop_back();
        }
    }
};

10.30 最小栈 lc 155

两个栈辅助的

class MinStack {
public:
    stack<int> stk;
    stack<int> minstack;
    MinStack() {

    }
    
    void push(int val) {
        stk.push(val);
        if(minstack.empty() || val <= minstack.top())
            minstack.push(val);
    }
    
    void pop() {
        int x = stk.top();
        cout << x << endl;
        stk.pop();
        if(minstack.size() && x == minstack.top())
            minstack.pop();
    }
    
    int top() {
        return stk.top();
    }
    
    int getMin() {
        cout << minstack.top() << endl;
        return minstack.top();
    }
};

链表解决的:头插法,每个节点中记录栈顶当前值和当前值作为栈顶时的最小值。

struct node
{
    int val;
    int min;
    node* next;
    node(int x, int y)
    {
        val = x;
        min = y;
        next = nullptr;
    }
};
class MinStack {
public:
    node* head;
    MinStack() {
        head = nullptr;
    }
    
    void push(int val) {
        if(head == nullptr)
            head = new node(val, val);
        else
        {
            int m = val <= head->min? val: head->min;
            node* tmp = new node(val, m);
            tmp->next = head;
            head = tmp; 
        }
    }
    
    void pop() {
        head = head->next;
    }
    
    int top() {
        return head->val;
    }
    
    int getMin() {
        return head->min;
    }
};

10.31 滑动窗口的最大值 lc 239

模拟滑动窗口不行因为如果排出最大值要重新遍历找最大值,会超时

因此,选择双向队列维护一个单调递减的队列,当删掉的值==左边最大值时,将其删掉.当加入的值大于队尾的值时,删掉队尾维持递减队列.

class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        vector<int> ans;
        int n = nums.size();
        deque<int> q;
        int l = 0, r = k - 1;
        for(int i = l; i <= r; i++)
        {
            while(q.size() && nums[i] > q.back())
                q.pop_back();
            if(!q.size() || nums[i] <= q.back())
                q.push_back(nums[i]);
        }
        ans.push_back(q.front());
        while(r + 1 < n)
        {
            if(q.size() && nums[l] == q.front())
                q.pop_front();

            while(q.size() && nums[r + 1] > q.back())
                q.pop_back();
            q.push_back(nums[r + 1]);
            ans.push_back(q.front());
            l++;
            r++;
        }
        return ans;
    }
};

10.31 神奇字符串 lc481

模拟题目即可,小技巧 1^3 = 2 2^3 = 1

class Solution {
public:
    int magicalString(int n) {
        int x1 = 3, x2 = 3;  //x1是总的字符串数量,x2是生成到哪一个
        vector<int> s(4, 0);
        s[1] = 1; s[2] = 2; s[3] = 2;
        int cnt = 1, f = 1;;
        while(x1 < n)
        {
            int t = 0;
            if(s[x2] == 1)
            {
                s.push_back(f);
                cnt += (f == 1);
                x1++;
            }
            else
            {
                s.push_back(f);
                s.push_back(f);
                x1 += 2;
                cnt += (f == 1) * 2;
            }
            f = f ^ 3;
            x2++;
        } 
        if(x1 > n && s[x1] == 1) cnt--;
        return cnt;
    }
};

10.31 课程表 lc 207

气死我了,一个拓扑排序写了这么久…

const int N = 5010;
int h[N], e[N], ne[N], idx;
void add(int a, int b)
{
    e[idx] = b; ne[idx] = h[a]; h[a] = idx++;
}
class Solution {
public:
    bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
        //if(prerequisites.size() == 1 && prerequisites[0][0] != p[])
        idx = 0;
        int cnt = 0;
        int inorder[numCourses];
        memset(inorder, 0, sizeof inorder);
        memset(h, -1, sizeof h);
        for(auto x: prerequisites)
        {
            if(x[0] == x[1])
                return false;
            add(x[0], x[1]);
            inorder[x[1]]++;
        }
        queue<int> q;
        int f = 0;
        for(int i = 0; i < numCourses; i++)
        {
            if(inorder[i] == 0)
            {
                q.push(i);
                inorder[i] = -1;
            }
        }
        while(q.size())
        {
            int b = q.front();
                q.pop();
                cnt++;
                for(int k = h[b]; k != -1; k = ne[k])
                {
                    int a = e[k];
                    inorder[a]--;
                    if(!inorder[a])
                        q.push(a);
                }
        }
        if(cnt < numCourses)
            return false;
        else
            return true;
        
    }
};

组合题目

1. 与下标相关的

2. 前缀和

3. 01背包

4. 单调栈

一些有的没的

  1. 字符串转int atoi()但是还需要从string 转到char : s.c_str()

    即 int x = atoi(s.c_str());

    int转string : string s = to_string(x);

    1. priority_queue

文章目录

  • 每日打卡
    • 10.1 [重新格式化电话号码 lc1694]([1694. 重新格式化电话号码 - 力扣(LeetCode)](https://leetcode.cn/problems/reformat-phone-number/))
    • 10.2 [在LR字符串中交换相邻字符 lc 777]([777. 在LR字符串中交换相邻字符 - 力扣(LeetCode)](https://leetcode.cn/problems/swap-adjacent-in-lr-string/))
    • 10.2 [每日温度 lc739]([739. 每日温度 - 力扣(LeetCode)](https://leetcode.cn/problems/daily-temperatures/))
    • 10.3 [检查二进制字符串字段 lc1784]([1784. 检查二进制字符串字段 - 力扣(LeetCode)](https://leetcode.cn/problems/check-if-binary-string-has-at-most-one-segment-of-ones/))
    • 10.3 [柱状图中的最大矩形 lc 84]([84. 柱状图中最大的矩形 - 力扣(LeetCode)](https://leetcode.cn/problems/largest-rectangle-in-histogram/))
    • 10.3 [最大矩形 lc85]([85. 最大矩形 - 力扣(LeetCode)](https://leetcode.cn/problems/maximal-rectangle/))
    • 10.4 [使括号有效的最少添加 lc 921]([921. 使括号有效的最少添加 - 力扣(LeetCode)](https://leetcode.cn/problems/minimum-add-to-make-parentheses-valid/))
    • 10.4 [最短无序连续子数组 lc 581] ([581. 最短无序连续子数组 - 力扣(LeetCode)](https://leetcode.cn/problems/shortest-unsorted-continuous-subarray/))
    • 10.5 [子域名访问计数 lc 811]([811. 子域名访问计数 - 力扣(LeetCode)](https://leetcode.cn/problems/subdomain-visit-count/))
    • [10.5 盛最多水的容器 lc 11]([11. 盛最多水的容器 - 力扣(LeetCode)](https://leetcode.cn/problems/container-with-most-water/))
    • [10.5 删掉链表的倒数第n个节点 lc 19]([19. 删除链表的倒数第 N 个结点 - 力扣(LeetCode)](https://leetcode.cn/problems/remove-nth-node-from-end-of-list/))
    • [10.6 三等分 lc 927]([927. 三等分 - 力扣(LeetCode)](https://leetcode.cn/problems/three-equal-parts/))
    • [10.6 下一个排列 lc 31]([31. 下一个排列 - 力扣(LeetCode)](https://leetcode.cn/problems/next-permutation/))
    • [10.7 最大升序子序列和 lc1800]([1800. 最大升序子数组和 - 力扣(LeetCode)](https://leetcode.cn/problems/maximum-ascending-subarray-sum/))
    • [10.7 寻找重复数 lc 287]([287. 寻找重复数 - 力扣(LeetCode)](https://leetcode.cn/problems/find-the-duplicate-number/))
    • [10.7 找到数组中消失的数字 lc 448]([448. 找到所有数组中消失的数字 - 力扣(LeetCode)](https://leetcode.cn/problems/find-all-numbers-disappeared-in-an-array/))
    • [10.8 优势洗牌 lc 870]([870. 优势洗牌 - 力扣(LeetCode)](https://leetcode.cn/problems/advantage-shuffle/))
    • !10.8 三数之和 lc 15
    • [10.10 数组中第k个元素]([215. 数组中的第K个最大元素 - 力扣(LeetCode)](https://leetcode.cn/problems/kth-largest-element-in-an-array/submissions/))
      • 1. 快速排序
      • 2. 建堆
    • 10.10 使序列递增的最小交换次数 lc 801
    • 10.11 仅执行一次字符串交换能否使两个字符串相等 lc 1790
    • 10.12 链表组件 lc 817
    • 10.12 接雨水 lc 42
    • 10.13 合并K个升序链表 lc 23
    • 10.13 [找到字符串中所有字母异位词](https://leetcode.cn/problems/find-all-anagrams-in-a-string/) lc 438
    • 10.13 最多能完成排序的块 lc 769
    • !10.14 不同的子序列 lc940
    • 10.14 路径总和 I lc 112
    • 10.14 路径总和II lc 113
    • 10.14 路径总和III lc 437
    • 10.14 二叉树的序列化与反序列化 lc 297
      • BFS
      • DFS
    • 10.15 目标和 lc494
      • 1.简单dfs
      • 2. dfs+记忆化搜索
      • 3. 01背包
    • 10.15 分割等和子集 lc 416
    • !10.15 用栈操作构建数组 lc 1441
    • !10.16 可能的二分法 lc 886
    • 10.17 完全平方数
    • 10.17 零钱兑换 lc 322
    • !10.17 水果成篮 lc 904
    • !10.18 最大为 N 的数字组合 lc 902
    • 10.18 环形链表 lc 141
    • 10.18 环形链表|| lc 142
    • 10.18 删除链表的倒数第 N 个结点 lc 19
    • !10.19 无法吃午餐肉的同学 lc 1700
    • !10.19 括号的生成 lc 22
    • !10.19 组合总和 lc 39
    • !10.19 组合总数 II lc 42
    • !10.19 电话号码的字母组合 lc 17
    • 10.20 缺失的第一个正数 lc 41
    • 10.20 寻找重复数 lc 287
    • 10.20 找到所有数组中消失的数字 lc 448
    • !10.20 第K个语法符号lc 779
    • !10.21 股票价格跨度 lc 901
    • !10.22 根据身高重建队列 lc 406
    • !10.22 规划兼职工作lc 1235
    • !10.24 除自身以外的乘积 lc 238
    • !10.24 和为k的子数组 lc 560
    • !10.24 分割数组 lc 915
    • !10.25 最短的桥
    • !10.26 任务调度器 lc 621
    • !10.26 和至少为k的最短子数组 lc 862
    • !10.28 戳气球 lc 312
    • !10.28 子数组的最小值之和 lc 907
    • 10.30 LRU缓存 lc 146
    • 10.30 字母大小写全排列 lc 784
    • 10.30 最小栈 lc 155
    • 10.31 滑动窗口的最大值 lc 239
    • 10.31 神奇字符串 lc481
    • 10.31 课程表 lc 207
  • 组合题目
    • 1. 与下标相关的
    • 2. 前缀和
    • 3. 01背包
    • 4. 单调栈
  • 一些有的没的
  • 每日打卡
    • 10.1 [重新格式化电话号码 lc1694]([1694. 重新格式化电话号码 - 力扣(LeetCode)](https://leetcode.cn/problems/reformat-phone-number/))
    • 10.2 [在LR字符串中交换相邻字符 lc 777]([777. 在LR字符串中交换相邻字符 - 力扣(LeetCode)](https://leetcode.cn/problems/swap-adjacent-in-lr-string/))
    • 10.2 [每日温度 lc739]([739. 每日温度 - 力扣(LeetCode)](https://leetcode.cn/problems/daily-temperatures/))
    • 10.3 [检查二进制字符串字段 lc1784]([1784. 检查二进制字符串字段 - 力扣(LeetCode)](https://leetcode.cn/problems/check-if-binary-string-has-at-most-one-segment-of-ones/))
    • 10.3 [柱状图中的最大矩形 lc 84]([84. 柱状图中最大的矩形 - 力扣(LeetCode)](https://leetcode.cn/problems/largest-rectangle-in-histogram/))
    • 10.3 [最大矩形 lc85]([85. 最大矩形 - 力扣(LeetCode)](https://leetcode.cn/problems/maximal-rectangle/))
    • 10.4 [使括号有效的最少添加 lc 921]([921. 使括号有效的最少添加 - 力扣(LeetCode)](https://leetcode.cn/problems/minimum-add-to-make-parentheses-valid/))
    • 10.4 [最短无序连续子数组 lc 581] ([581. 最短无序连续子数组 - 力扣(LeetCode)](https://leetcode.cn/problems/shortest-unsorted-continuous-subarray/))
    • 10.5 [子域名访问计数 lc 811]([811. 子域名访问计数 - 力扣(LeetCode)](https://leetcode.cn/problems/subdomain-visit-count/))
    • [10.5 盛最多水的容器 lc 11]([11. 盛最多水的容器 - 力扣(LeetCode)](https://leetcode.cn/problems/container-with-most-water/))
    • [10.5 删掉链表的倒数第n个节点 lc 19]([19. 删除链表的倒数第 N 个结点 - 力扣(LeetCode)](https://leetcode.cn/problems/remove-nth-node-from-end-of-list/))
    • [10.6 三等分 lc 927]([927. 三等分 - 力扣(LeetCode)](https://leetcode.cn/problems/three-equal-parts/))
    • [10.6 下一个排列 lc 31]([31. 下一个排列 - 力扣(LeetCode)](https://leetcode.cn/problems/next-permutation/))
    • [10.7 最大升序子序列和 lc1800]([1800. 最大升序子数组和 - 力扣(LeetCode)](https://leetcode.cn/problems/maximum-ascending-subarray-sum/))
    • [10.7 寻找重复数 lc 287]([287. 寻找重复数 - 力扣(LeetCode)](https://leetcode.cn/problems/find-the-duplicate-number/))
    • [10.7 找到数组中消失的数字 lc 448]([448. 找到所有数组中消失的数字 - 力扣(LeetCode)](https://leetcode.cn/problems/find-all-numbers-disappeared-in-an-array/))
    • [10.8 优势洗牌 lc 870]([870. 优势洗牌 - 力扣(LeetCode)](https://leetcode.cn/problems/advantage-shuffle/))
    • !10.8 三数之和 lc 15
    • [10.10 数组中第k个元素]([215. 数组中的第K个最大元素 - 力扣(LeetCode)](https://leetcode.cn/problems/kth-largest-element-in-an-array/submissions/))
      • 1. 快速排序
      • 2. 建堆
    • 10.10 使序列递增的最小交换次数 lc 801
    • 10.11 仅执行一次字符串交换能否使两个字符串相等 lc 1790
    • 10.12 链表组件 lc 817
    • 10.12 接雨水 lc 42
    • 10.13 合并K个升序链表 lc 23
    • 10.13 [找到字符串中所有字母异位词](https://leetcode.cn/problems/find-all-anagrams-in-a-string/) lc 438
    • 10.13 最多能完成排序的块 lc 769
    • !10.14 不同的子序列 lc940
    • 10.14 路径总和 I lc 112
    • 10.14 路径总和II lc 113
    • 10.14 路径总和III lc 437
    • 10.14 二叉树的序列化与反序列化 lc 297
      • BFS
      • DFS
    • 10.15 目标和 lc494
      • 1.简单dfs
      • 2. dfs+记忆化搜索
      • 3. 01背包
    • 10.15 分割等和子集 lc 416
    • !10.15 用栈操作构建数组 lc 1441
    • !10.16 可能的二分法 lc 886
    • 10.17 完全平方数
    • 10.17 零钱兑换 lc 322
    • !10.17 水果成篮 lc 904
    • !10.18 最大为 N 的数字组合 lc 902
    • 10.18 环形链表 lc 141
    • 10.18 环形链表|| lc 142
    • 10.18 删除链表的倒数第 N 个结点 lc 19
    • !10.19 无法吃午餐肉的同学 lc 1700
    • !10.19 括号的生成 lc 22
    • !10.19 组合总和 lc 39
    • !10.19 组合总数 II lc 42
    • !10.19 电话号码的字母组合 lc 17
    • 10.20 缺失的第一个正数 lc 41
    • 10.20 寻找重复数 lc 287
    • 10.20 找到所有数组中消失的数字 lc 448
    • !10.20 第K个语法符号lc 779
    • !10.21 股票价格跨度 lc 901
    • !10.22 根据身高重建队列 lc 406
    • !10.22 规划兼职工作lc 1235
    • !10.24 除自身以外的乘积 lc 238
    • !10.24 和为k的子数组 lc 560
    • !10.24 分割数组 lc 915
    • !10.25 最短的桥
    • !10.26 任务调度器 lc 621
    • !10.26 和至少为k的最短子数组 lc 862
    • !10.28 戳气球 lc 312
    • !10.28 子数组的最小值之和 lc 907
    • 10.30 LRU缓存 lc 146
    • 10.30 字母大小写全排列 lc 784
    • 10.30 最小栈 lc 155
    • 10.31 滑动窗口的最大值 lc 239
    • 10.31 神奇字符串 lc481
    • 10.31 课程表 lc 207
  • 组合题目
    • 1. 与下标相关的
    • 2. 前缀和
    • 3. 01背包
    • 4. 单调栈
  • 一些有的没的

每日打卡

10.1 [重新格式化电话号码 lc1694](1694. 重新格式化电话号码 - 力扣(LeetCode))

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wAvE3rWA-1668235849917)(10_leetcode.assets/image-20221004181510443.png)]

模拟题:特殊情况就是在最后划分完全部三个之后,还剩四个需要变成aa-bb

class Solution {
public:
    string reformatNumber(string number) {
        string ans;
        queue<char> q;
        for(char ch: number)
        {
            if(ch != ' ' && ch != '-')
                q.push(ch);
        }
        int cnt = 0;
        while(q.size())
        {
            if(cnt == 0 && q.size() == 4)
            {
                ans += q.front();
                q.pop();
                ans += q.front();
                q.pop();
                ans += '-';
                ans += q.front();
                q.pop();
                ans += q.front();
                q.pop();
            }
            if(!q.size())
                break;
            if(cnt == 3)
            {
                ans += '-';
                cnt = 0;
            }
            else
            {
                ans += q.front();
                q.pop();
                cnt++;
            }
        }
        return ans;
    }
};

10.2 [在LR字符串中交换相邻字符 lc 777](777. 在LR字符串中交换相邻字符 - 力扣(LeetCode))

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6UBeYqNz-1668235849918)(10_leetcode.assets/image-20221004182709177.png)]

题目的意思是L可以越过X向左移动,R可以越过X向右移动。

!也就是去掉X后start和end字符串的L和R位置相同!

class Solution {
public:
    bool canTransform(string start, string end) {
        int n = start.size();
        int i = 0, j = 0;
        while(1)
        {
            //越过所有的X
            while(i < n && start[i] == 'X')
                i++;
            while(j < n && end[j] == 'X')
                j++;
            //判断现在的i和j情况
            //如果两个都走到底了那可以
            if(i == n && j == n)
                return true;
            //有一个走到底了另一个没有或者二者对应的不相同那不行
            if(i == n || j == n || start[i] != end[j])
                return false;
            //两者的位置不同也不行L可以左移所以start的可以在end后面
            if(start[i] == 'L' && i < j)
                return false;
            //R可以右移所以start的可以在end前面
            if(start[i] =='R' && i > j)
                return false;
            i++;
            j++;
        }
        return true;
    }
};

10.2 [每日温度 lc739](739. 每日温度 - 力扣(LeetCode))

单调栈

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iCARaYR0-1668235849919)(10_leetcode.assets/image-20221005202544978.png)]

明显的单调栈就是说维持这个栈单调递减,如果出现比栈顶大的元素,说明下一个更高温度已经出现,可以将其pop出来了。

可以在栈底设置一个哨兵0,这样便于处理边界

class Solution {
public:
    vector<int> dailyTemperatures(vector<int>& temp) {
        int n = temp.size();
        vector<int> ans(n, 0);
        stack<int> stk;
        stk.push(0);
        for(int i = 1; i < n; i++)
        {
            while(!stk.empty() && temp[stk.top()] < temp[i])
            {
                ans[stk.top()] = i - stk.top();
                stk.pop();
            }
            stk.push(i);
        }
        return ans;
    }
};

10.3 [检查二进制字符串字段 lc1784](1784. 检查二进制字符串字段 - 力扣(LeetCode))

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qbh8LXzL-1668235849919)(10_leetcode.assets/image-20221005203538687.png)]

题目含义很难理解,看了评论区之后:连续若干个"1"组成的字段是由一个或者多个连续‘1’组成的,如果这样的字段不超过1个,就返回true,多于1个就返回false。

1000 true 110001 false 统计即可

class Solution {
public:
    bool checkOnesSegment(string s) {
        int cnt = 0;
        int n = s.size();
        int len = 0;
        for(int i = 0; i < n; i++)
        {
            while(i < n && s[i] == '1')
            {
                len++;
                i++;
            }
            if(len >= 1)
                cnt++;
            if(i < n && s[i] == '0')
                len = 0;
            
        }
        return cnt <= 1;
    }
};

10.3 [柱状图中的最大矩形 lc 84](84. 柱状图中最大的矩形 - 力扣(LeetCode))

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oaM2Udkf-1668235849920)(10_leetcode.assets/image-20221005203952026.png)]

我们之前做过一个类似的,盛最多水的容器,那个是构造的矩形是两个边界中最小即可,也即是双指针就行。这个不一样的是你需要使用整个容器内的最矮的作为高。所以我们想遍历每个柱子,以其作为高h,然后去寻找最宽的边,也即是向两边分别找高于h的柱子,找到第一个低于h的就停止。

这个也是单调栈,对于单调递增的栈来说:栈里的前一个元素就是左边第一个小于该元素的值,右边第一个小于我们可以在比较中得到。当发现小于栈顶元素时就可以得到右边第一个了,否则就加入栈中即可。

class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        int n = heights.size() + 2;
        //向两边加一个哨兵
        heights.insert(heights.begin(), 0);
        heights.push_back(0);
        int ans = 0;
        stack<int> s;
        for(int i = 0; i < n; i++)
        {
            while(!s.empty() && heights[i] < heights[s.top()])
            {
                int j = s.top();
                s.pop();
                ans = max(ans, heights[j] * (i - s.top() - 1));
            }
            s.push(i);
        }
        return ans;
    }
};

10.3 [最大矩形 lc85](85. 最大矩形 - 力扣(LeetCode))

就是上面lc84的二维版本

最形象的图就是这个

只用第一行高度是 1 0 1 0 0

12行高度是 2 0 2 1 1

13行高度是 3 1 3 2 2

这几行分别调用lc84即可取最大即可!

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vA50RrVH-1668235849921)(10_leetcode.assets/image-20221005214334845.png)]

class Solution {
public:
    int maximalRectangle(vector<vector<char>>& matrix) {
        int row = matrix.size(), col = matrix[0].size();
        if(row == 0 || col == 0)
            return 0;
        int ans = 0;
        vector<int> height(col, 0);
        for(int i = 0; i < row; i++)
        {
            for(int j = 0; j < col; j++)
            {
                if(matrix[i][j] == '1')
                    height[j] =  height[j] + 1;
                else
                    height[j] = 0;
            }
            for(int x: height)
                cout << x << " ";
            cout << endl;
            ans = max(ans, largestRectangleArea(height));
        }
        return ans;
    }

    int largestRectangleArea(vector<int> heights) {
        int n = heights.size() + 2;
        heights.insert(heights.begin(), 0);
        heights.push_back(0);
        int ans = 0;
        stack<int> s;
        for(int i = 0; i < n; i++)
        {
            while(!s.empty() && heights[i] < heights[s.top()])
            {
                int j = s.top();
                s.pop();
                ans = max(ans, heights[j] * (i - s.top() - 1));
            }
            s.push(i);
        }
        return ans;
    }
};

10.4 [使括号有效的最少添加 lc 921](921. 使括号有效的最少添加 - 力扣(LeetCode))

这个就是有效的括号,但是由于是任意位置插入左括号和右括号都行,只需要数量对应上即可。左括号+1,右括号先抵消再计数即可

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0DCDvQ0T-1668235849922)(10_leetcode.assets/image-20221005214634211.png)]

class Solution {
public:
    int minAddToMakeValid(string s) {
        int l = 0, cnt = 0;
        for(char ch: s)
        {
            if(ch == '(')
                l++;
            else if(l > 0 && ch == ')')
                l--;
            else if(l == 0 && ch == ')')
                cnt++;
        }
        return cnt + l;
    }
};

10.4 [最短无序连续子数组 lc 581] (581. 最短无序连续子数组 - 力扣(LeetCode))

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PgaH4OOF-1668235849922)(10_leetcode.assets/image-20221005214906449.png)]

这个看起来很简单,本来想着从两边向中间扩展出现无序就停止来着,但是其中的等号很麻烦。这个题一点都不简单。

两个边界l, r。l是最左边需要开始排序的数,应该从右边开始遍历。如果不需要排序的话,那么从右边开始应该每一个数nums[j]都小于等于右边遍历过的min。反之若nums[j] > min的话,就需要记录下来需要排序的值l。

同理,r是最右边需要开始排序的数,应该从左边开始遍历。如果不需要排序的话,那么从左边开始应该每一个数nums[i]都大于等于左边遍历过前i - 1个数的max。反之若nums[j] < max的话,就需要记录下来需要排序的值r。

class Solution {
public:
    int findUnsortedSubarray(vector<int>& nums) {
        int n = nums.size();
        int ma = INT_MIN, mi = INT_MAX;
        int l = 0, r = 0;
        for(int i = 0; i < n; i++)
        {
            if(nums[i] < ma)
                r = i;
            else
                ma = max(ma, nums[i]);
        }
        for(int j = n - 1; j >= 0; j--)
        {
            if(nums[j] > mi)
                l = j;
            else
                mi = min(mi, nums[j]);
        } 
        if(l == r)
            return 0;
        else
            return r - l + 1;
    }
};

10.5 [子域名访问计数 lc 811](811. 子域名访问计数 - 力扣(LeetCode))

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JJIdJMUp-1668235849923)(10_leetcode.assets/image-20221005210843421.png)]

简单模拟:使用hashmap的key存储域名,value存储个数,处理字符串计数即可。

class Solution {
public:
    vector<string> subdomainVisits(vector<string>& cpdomains) {
        unordered_map<string, int> hashMap;
        vector<string> ans;
        for(string s: cpdomains)
        {
            int i = 0;
            while(i < s.size() && s[i] != ' ')
                i++;
            int cnt = atoi(s.substr(0, i).c_str());
            string s1 = s.substr(++i);  //google.mail.com
            if(hashMap.find(s1) != hashMap.end())
                hashMap[s1] += cnt;
            else
                hashMap[s1] = cnt;
            while(i < s.size() && s[i] != '.')
                i++;
            string s2 = s.substr(++i); //mail.com
            if(hashMap.find(s2) != hashMap.end())
                hashMap[s2] += cnt;
            else
                hashMap[s2] = cnt;
            while(i < s.size() && s[i] != '.')
                i++;
            if(i < s.size() && s[i] == '.')
            {
                string s3 = s.substr(++i); //com
                if(hashMap.find(s3) != hashMap.end())
                    hashMap[s3] += cnt;
                else
                    hashMap[s3] = cnt;
            }
        }
        for(auto x: hashMap)
        {
            string s = to_string(x.second) + " " + x.first;
            ans.push_back(s);
        }
        return ans;
    }
};

[10.5 盛最多水的容器 lc 11](11. 盛最多水的容器 - 力扣(LeetCode))

这个就很简单啦,双指针遍历一下

class Solution {
public:
    int maxArea(vector<int>& height) {
        int n = height.size();
        int i = 0, j = n - 1;
        int ans = 0;
        while(i < j)
        {
            int s = min(height[i], height[j]) * (j - i);
            ans = max(ans, s);
            if(height[i] < height[j])
                i++;
            else
                j--;
        }
        return ans;
    }
};

[10.5 删掉链表的倒数第n个节点 lc 19](19. 删除链表的倒数第 N 个结点 - 力扣(LeetCode))

也很简单啦,就是快慢指针先找到倒数第n个节点,然后删除即可。

注意一些边界条件,比如删除头节点、删除只有一个元素的链表等

/**
 * 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* removeNthFromEnd(ListNode* head, int n) {
        ListNode* p = head;
        if(head->next == nullptr)
            return nullptr;
        for(int i = 0; i < n; i++)
            p = p->next;
        ListNode* q = head;
        if(p == nullptr)
            return head->next;  //删掉头节点

        while(p->next != nullptr)
        {
            p = p->next;
            q = q->next;
        }
        ListNode* nx = q->next;
        q->next = nx->next; 
        return head;
    }
};

[10.6 三等分 lc 927](927. 三等分 - 力扣(LeetCode))

三个指针判断三部分是否相等,二进制是否相等首先看1的个数,其次看第一个1后的排列是否相等。`

class Solution {
public:
    vector<int> threeEqualParts(vector<int>& arr) {
        vector<int> ans = {-1, -1};
        int n = arr.size();
        int cnt = 0;
        //求出所有1的数量
        for(int i = 0; i < n; i++)
            cnt += arr[i];
        if(cnt == 0)
            return {0, n - 1};
        //三者平分 能分继续 不能分就不行
        if(cnt % 3) return ans;
        cnt = cnt / 3;
        int i = 0, j = 0, k = 0, s = 0;
        //根据1的数量将三个指针定位到各自第一个1的位置
        while(i < n && s < 1) { s += arr[i++];}
        s = 0;
        while(j < n && s < cnt + 1)  { s += arr[j++];}
        s = 0;
        while(k < n && s < 2 * cnt + 1)  { s += arr[k++];}

        //开始判断第一个1后面的是否完全相同
        while(k < n && arr[i] == arr[j] && arr[j] == arr[k])
        {
            i++; j++; k++;
        }
        if(k < n)
            return ans;
        else
            return {i - 1, j};

    }
};

[10.6 下一个排列 lc 31](31. 下一个排列 - 力扣(LeetCode))

这个题挺巧妙的,需要仔细分析排列。我们以2 6 3 5 4 1为例,可以从右边开始分析。就是如果是降序比如5 4 1这样的,就是已经是最大的了,不会再有下一个排列了。所以我们第一步需要从右边找第一个升序的,找到了 3 5。为了是下一个排列因此我们需要使这个排列尽可能地小,所以我们从后面5 4 1中选一个第一个比3大地和他交换,得到一个比3大一点的新开头,2 6 4 5 3 1。接下来需要将后面的变成最小的,因为是逆序,所以直接反转即可。

class Solution {
public:
    void nextPermutation(vector<int>& nums) {
        int n = nums.size();
        int i = n - 1;
        //找到第一个升序的 3 5 
        while(i > 0 && nums[i] <= nums[i - 1]) i--;
        //如果不存在升序说明全部倒序,直接全部逆序即可
        if(i <= 0) {reverse(nums.begin(), nums.end()); return;}
        int j = i - 1; // j是3 等着待交换的那个
        //向右边倒序序列中找比nums[j]大一点的值 i - 1就是那个4
        while(i < n && nums[i] > nums[j]) i++;
        cout << nums[j] << " " << nums[i - 1] << endl;
        //swap(nums[j], nums[i - 1]); 将二者交换
        int t = nums[j];
        nums[j] = nums[i - 1];
        nums[i - 1] = t;
        //最后将后面的倒序逆转变小一点的排列
        reverse(nums.begin() + j + 1, nums.end());
    }
};

[10.7 最大升序子序列和 lc1800](1800. 最大升序子数组和 - 力扣(LeetCode))

class Solution {
public:
    int maxAscendingSum(vector<int>& nums) {
        int ans = nums[0], s = nums[0];
        for(int i = 1; i < nums.size(); i++)
        {
            if(nums[i - 1] < nums[i])
                s += nums[i];
            else
                s = nums[i];
            ans = max(ans, s);
        }
        return ans;
    }
};

[10.7 寻找重复数 lc 287](287. 寻找重复数 - 力扣(LeetCode))

快慢指针,将1,3,4,2,2看成链表,判断链表是否有环以及找到链表的入口。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YWXcDYdd-1668235849923)(10_leetcode.assets/image-20221018001113229.png)]

class Solution {
public:
    int findDuplicate(vector<int>& nums) {
        //将数组看成链表,找到环的入口
        int slow = 0, fast = 0;
        while(1)
        {
            slow = nums[slow];
            fast = nums[nums[fast]];
            if(slow == fast)
                break;
        }
        fast = 0;
        while(slow != fast)
        {
            slow = nums[slow];
            fast = nums[fast];
        }
        return slow;
    }
};

[10.7 找到数组中消失的数字 lc 448](448. 找到所有数组中消失的数字 - 力扣(LeetCode))

这个题也是将数组中的值和下标映射起来,比如[4,3,2,7,8,2,3,1],nums[0] = 4,则将4对应的nums[4] = 8换成-8代表有4了,重复的已经成为负数的就不变,最后值为正的下标就是消失的数字。

class Solution {
public:
    vector<int> findDisappearedNumbers(vector<int>& nums) {
        vector<int> ans;
        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)
                ans.push_back(i + 1);
        }
        return ans;
    }
};

[10.8 优势洗牌 lc 870](870. 优势洗牌 - 力扣(LeetCode))

贪心之田忌赛马:在nums1中找大于nums2[i]的最小值,如果没有则返回nums1中的最小值。直接找会导致超时,二分查找第一个。

class Solution {
public:
    vector<int> advantageCount(vector<int>& nums1, vector<int>& nums2) {
        int n = nums1.size();
        vector<int> ans(n, 0);
        bool st[n];
        int idx = 0;
        memset(st, false, sizeof st);
        sort(nums1.begin(), nums1.end());
        for(int i = 0; i < n; i++)
        {
            int l = 0, r = n;
            while(l < r)
            {
                int mid = l + r >> 1;
                if(nums1[mid] > nums2[i])
                    r = mid;
                else
                    l = mid + 1;
            }
            while(l < n && (st[l] || nums1[l] == nums2[i]))
                l++;
            if(l < n)
            {
                ans[i] = nums1[l];
                st[l] = true;
            }
            else
            {
                while(st[idx]) idx++;
                ans[i] = nums1[idx];
                st[idx++] = true;
            }
       }
        return ans; 
    }
};

!10.8 三数之和 lc 15

[10.10 数组中第k个元素](215. 数组中的第K个最大元素 - 力扣(LeetCode))

1. 快速排序

快速排序每次都可以使nums[r]== x,然后左侧都小于等于x,右侧都大于等于x。因此只要某次确定值的下标是k就可以返回第k个最大的元素了。

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        return quicksort(nums, k, 0, nums.size() - 1);
    }

    int quicksort(vector<int>& nums, int k, int left, int right)
    {
        if(right < left)
            return INT_MAX;
        int x = nums[(left + right) >> 1];
        int l = left - 1, r = right + 1;
        while(l < r)
        {
            do l++; while(nums[l] > x);
            do r--; while(nums[r] < x);
            if(l < r)
            {
                int t = nums[l]; nums[l] = nums[r]; nums[r] = t;
            }
        }
        int p;
        if(nums[l] == x)
            p = l;
        if(nums[r] == x)
            p = r;
        if(p == k - 1)
            return nums[p];
        else if(p > k - 1)
            return quicksort(nums, k, left, r);
        else
            return quicksort(nums, k, r + 1, right);
        
    }
};

2. 建堆

维护一个k长度的小顶堆,堆顶元素就是第k大,当堆顶元素不再是第k大的时候,就调整堆。

最小堆 - 数组中的第K个最大元素 - 力扣(LeetCode)

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        int n = nums.size();

        make_heap(nums, k);
        for(int i = k; i < n; i++)
        {
            if(nums[i] < nums[0])
                continue;
            else
            {
                nums[0] = nums[i];
                shift_down(nums, k, 0);
            }
        }
        return nums[0];
    }

    void shift_down(vector<int>& nums, int k, int i)
    {
        int j = 2 * i + 1;
        while(j < k)
        {
            if(j + 1 < k && nums[j] > nums[j + 1]) j++;
            if(nums[i] > nums[j])
            {
                swap(nums[i], nums[j]);
                i = j;
                j = 2 * i + 1;
            }
            else
                break;
        }
    }
    void make_heap(vector<int>& nums, int k)
    {
        for(int i = k / 2; i >= 0; i--)
            shift_down(nums, k, i);
    }
};

10.10 使序列递增的最小交换次数 lc 801

状态机dp:dp[i] [0]表示第i位不发生交换使得前i位递增的最小交换次数,1同理。

有两种情况可以交换:

  • 两组都满足前后大于,这种就是要不i和i-1都不交换,要么都交换。
  • 交叉满足前后大小关系,这种要不i- 1交换要不i交换。
class Solution {
public:
    int minSwap(vector<int>& nums1, vector<int>& nums2) {
        int n = nums1.size();
        int dp[n][2];
        memset(dp, 0x3f, sizeof dp);
        dp[0][0] = 0;
        dp[0][1] = 1;
        for(int i = 1; i < n; i++)
        {
            if(nums1[i] > nums1[i - 1] && nums2[i] > nums2[i - 1])
            {
                dp[i][0] = dp[i - 1][0];  //要么不交换
                dp[i][1] = dp[i - 1][1] + 1; //要么两个都交换
            }
            if(nums1[i] > nums2[i - 1] && nums2[i] > nums1[i - 1])
            {
                dp[i][0] = min(dp[i][0], dp[i - 1][1]);  //前一个发生交换
                dp[i][1] = min(dp[i][1], dp[i - 1][0] + 1); //后面这个发生交换
            }
        }
        return min(dp[n - 1][0], dp[n - 1][1]);
    }
};

10.11 仅执行一次字符串交换能否使两个字符串相等 lc 1790

记录下两个不同的下标,超过两个不同返回false,最后看不同的两个下标交换后是否相同。

class Solution {
public:
    bool areAlmostEqual(string s1, string s2) {
        int n = s1.size();
        int cnt = 0;
        int a[2];
        for(int i = 0; i < n; i++)
        {
            if(s1[i] != s2[i])
            {
                if(cnt == 2)
                {
                    cnt++;
                    break;
                }
                a[cnt++] = i;
            }
        }
        if(cnt == 1 || cnt > 2)
            return false;
        if(cnt == 0)
            return true;
        if(s1[a[0]] == s2[a[1]] && s1[a[1]] == s2[a[0]])
            return true;
        return false;
    }
};

10.12 链表组件 lc 817

模拟即可

/**
 * 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:
// 被骗了,是求所有组件的个数而不是求组件的最大长度无语无语
    int numComponents(ListNode* head, vector<int>& nums) {
        int n = nums.size(), ans = 0;
        unordered_set<int> hashset;
        for(int x: nums)
            hashset.insert(x);
        ListNode* p = head;
        int cnt = 0;
        while(p != nullptr)
        {
            if(hashset.find(p->val) != hashset.end())
                cnt++;
            else
            {
                if(cnt)
                    ans++;
                cnt = 0;
                
            }
            p = p->next;
        }
        if(cnt)
            ans++;
        return ans;
    }
};

10.12 接雨水 lc 42

接雨水的关键就是单调栈

不同于柱状图的最大矩形(向两边找低于栈顶的递增),接雨水需要向两边找高于栈顶的,这样才能接住雨水,因此是递减栈。

以栈顶元素作为雨水高度t = height[stk.top()],当右边高于栈顶时,就是找到了右边高于的,然后去找左边高于的,也即是下一个栈顶。还有要是有和栈顶相同的也要pop出去,而且高度要减去。下一个栈顶就是左边高于栈顶的了height[stk.top()]。比较这两边高的选小的作为高,减去t,乘上宽度即可。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b9ehoulr-1668235849924)(10_leetcode.assets/image-20221021204205650.png)]

class Solution {
public:
    int trap(vector<int>& height) {
        int n = height.size();
        int ans = 0;
        stack<int> stk;
        for(int i = 0; i < n; i++)
        {
            while(!stk.empty() && height[i] > height[stk.top()])
            {
                int t = stk.top();
                stk.pop();
                while(!stk.empty() && height[stk.top()] == height[t])
                    stk.pop();
                if(!stk.empty())
                    ans += ( min(height[stk.top()], height[i]) - height[t] ) * (i - stk.top() - 1);
            }
            stk.push(i);
        }
        return ans;
    }
};

10.13 合并K个升序链表 lc 23

两两归并,最后变成两个合并。

/**
 * 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* mergeTwoLists(ListNode* l1, ListNode* l2)
    {
        ListNode* dummy = new ListNode(-1);
        ListNode* p = dummy;
        if(l1 == nullptr && l2 == nullptr)
            return nullptr;
        while(l1 != nullptr && l2 != nullptr)
        {
            if(l1->val < l2->val)
            {
                p->next = l1;
                l1 = l1->next;
            }
            else
            {
                p->next = l2;
                l2 = l2->next;
            }
            p = p->next;
        }
        while(l1 != nullptr)
        {
            p->next = l1;
            l1 = l1->next;
            p = p->next;
        }
        while(l2 != nullptr)
        {
            p->next = l2;
            l2 = l2->next;
            p = p->next;
        }
        return dummy->next;
    }
    ListNode* binaryMerge(vector<ListNode*>& lists, int low, int high)
    {
        if(low > high)
            return nullptr;
        if(low == high)
            return lists[low];
        if(high - low == 1)
            return mergeTwoLists(lists[low], lists[high]);
        int mid = (low + high) >> 1;
        return mergeTwoLists(binaryMerge(lists, low, mid), binaryMerge(lists, mid + 1, high));
    }
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        return binaryMerge(lists, 0, lists.size() - 1);
    }
};

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qDfP7fK1-1668235849933)(image-20221027234642721.png)]

滑动窗口

class Solution {
public:
    vector<int> findAnagrams(string s, string p) {
        vector<int> ans;
        int sn = s.size();
        int pn = p.size();
        if(pn > sn) return {};
        int cnts[26];
        int cntp[26];
        memset(cnts, 0, sizeof cnts);
        memset(cntp, 0, sizeof cntp);
        for(int i = 0; i < pn; i++)
            cntp[p[i] - 'a']++;
        int i = 0, j = 0;
        for(; j < pn; j++)
            cnts[s[j] - 'a']++;
        while(j < sn)
        {
            bool f = true;
            for(int k = 0; k < 26; k++)
            {
                if(cnts[k] != cntp[k])
                    f = false;
            }
            if(f)
                ans.push_back(i);
            cnts[s[i++] - 'a']--;
            if(j < sn)
                cnts[s[j++] - 'a']++;  
        }
        bool f = true;
        for(int k = 0; k < 26; k++)
        {
            if(cnts[k] != cntp[k])
                f = false;
        }
        if(f)
            ans.push_back(i);
        return ans;
    }
};

10.13 最多能完成排序的块 lc 769

规律:区间数的最大值小于等于下标就可以分块

class Solution {
public:
    int maxChunksToSorted(vector<int>& arr) {
        //区间的最大值小于等于索引则可以划分区间
        int n = arr.size();
        int ans = 0, ma = 0;
        for(int i = 0; i < n; i++)
        {
            if(arr[i] > ma)
                ma = arr[i];
            if(ma <= i)
            {
                ans++;
                ma = 0;
            }
        }
        return ans;
    }
};

!10.14 不同的子序列 lc940

10.14 路径总和 I lc 112

我一开始写的是,先不管下面这个空树是否为空。看[1, 2] 1 这个例子,就是这棵树只有1 ,2 一侧两个节点。在我的判断中走到1这个节点就可以判断true了。但是题目要求的是到叶子节点,所以判断条件要加上节点的左右节点都为空。

//wrong
class Solution {
public:
    bool hasPathSum(TreeNode* root, int targetSum) {
        if(root == nullptr && targetsum == 0)
            return true;
        if(root == nullptr)
            return false;
        return hasPathSum(root->left, targetSum - root->val) || hasPathSum(root->right, targetSum - root->val);
    }
};
//right
class Solution {
public:
    bool hasPathSum(TreeNode* root, int targetSum) {
        if(root == nullptr)
            return false;
        if(targetSum == root->val && root->left == nullptr && root->right == nullptr)
            return true;
        return hasPathSum(root->left, targetSum - root->val) || hasPathSum(root->right, targetSum - root->val);
    }
};

10.14 路径总和II lc 113

在1的基础上要记录下满足要求的路径和

class Solution {
public:
    vector<vector<int>> ans;
    vector<int> tmp;
    vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
        if(root == nullptr)
            return {};
        helper(root, targetSum);
        return ans;
    }
    void helper(TreeNode* root, int targetSum)
    {
        if(root == nullptr)
            return;
        if(targetSum == root->val && !root->left && !root->right)
        {
            tmp.push_back(root->val);
            ans.push_back(tmp);
            tmp.pop_back();
            return ;
        }
        tmp.push_back(root->val);
        helper(root->left, targetSum - root->val);
        helper(root->right, targetSum - root->val);
        tmp.pop_back();
    }
};

10.14 路径总和III lc 437

路径不需要从父节点开始,也不需要在叶子节点结束,但方向要向下。

两个dfs,第一个dfs遍历每个节点,第二dfs去计算和是否满足。

class Solution {
public:
    long long  ans = 0;
    int ts;
    int pathSum(TreeNode* root, int targetSum) {
        if(root == nullptr)
            return 0;
        ts = targetSum;
        dfs1(root);
        return ans;
    }
    void dfs1(TreeNode* root)
    {
        if(root == nullptr)
            return;
        dfs2(root, 0);
        dfs1(root->left);
        dfs1(root->right);
    }
    void dfs2(TreeNode* root, long long curSum)
    {
        if(root == nullptr)
            return;
        curSum += root->val;

        if(curSum == ts)
            ans++;
        
        dfs2(root->left, curSum);
        dfs2(root->right, curSum);
    }
};

树上的前缀和:哇塞!最完整的路径是从根节点到叶子节点,这题相当于在这些路径上找区间和=targetsum的,那不就是前缀和吗!

curSum - preSum = targetSum即可。

class Solution {
public:
    unordered_map<long long, int> preSum;
    int targetSum;
    int ans = 0;
    int pathSum(TreeNode* root, int ts) {
        if(root == nullptr)
            return 0;
        targetSum = ts;
        preSum[0] = 1;
        dfs(root, 0);
        return ans;
    }
    void dfs(TreeNode* root, long long curSum)
    {
        if(root == nullptr)
            return;
        curSum += root->val;
        if(preSum.find(curSum - targetSum) != preSum.end())
        {
            ans += preSum[curSum - targetSum];
        }
        preSum[curSum]++;
        dfs(root->left, curSum);
        dfs(root->right, curSum);
        preSum[curSum]--;
    }
};

10.14 二叉树的序列化与反序列化 lc 297

这道题主要是区分每个节点的值和null处理、负值处理的问题,其他就是递归即可

BFS

class Codec {
public:
    const int nll = 2000;
    // Encodes a tree to a single string.
    string serialize(TreeNode* root) {
        if(root == nullptr)
            return "";
        string data;
        queue<TreeNode*> q;
        q.push(root);
        while(q.size())
        {
            TreeNode* tmp = q.front();
            q.pop();
            if(tmp == nullptr)
            {
                data += "_#";
                continue;
            }
            data += "_" + to_string(tmp->val);
            q.push(tmp->left);
            q.push(tmp->right);
        }
        cout << data << endl;
        return data;
    }

    // Decodes your encoded data to tree.
    TreeNode* deserialize(string data) {
        if(data.size() == 0)
            return nullptr;
        vector<int> v;
        int i = 0;
        while(i < data.size())
        {
            int j = i + 1;
            while(j < data.size() && data[j] != '_')
                j++;
            string s = data.substr(i + 1, j - i - 1);
            cout << s << endl;
            if(s == "#")
                v.push_back(nll);
            else
                v.push_back(atoi(s.c_str()));
            i = j;
        }
        i = 0;
        TreeNode* root = new TreeNode(v[i++]);
        queue<TreeNode*> q;
        q.push(root);
        while(q.size())
        {
            TreeNode* tmp = q.front();
            q.pop();
            if(v[i] == nll)
                tmp->left = nullptr;
            else
            {
                tmp->left = new TreeNode(v[i]);
                q.push(tmp->left);
            }
            i++;
            if(v[i] == nll)
                tmp->right = nullptr;
            else
            {
                tmp->right = new TreeNode(v[i]);
                q.push(tmp->right);
            }
            i++;
        }
        return root;
    }
};

DFS

class Codec {
public:
    const int nll = 2000;
    vector<int> v;
    int i = 1;
    // Encodes a tree to a single string.
    string serialize(TreeNode* root) {
        if(root == nullptr)
            return "_#";
        return "_" + to_string(root->val) +  serialize(root->left) + serialize(root->right);
    }
    void helper(string data)
    {
        int i = 0;
        while(i < data.size())
        {
            int j = i + 1;
            while(j < data.size() && data[j] != '_')
                j++;
            string s = data.substr(i + 1, j - i - 1);
            cout << s << endl;
            if(s == "#")
                v.push_back(nll);
            else
                v.push_back(atoi(s.c_str()));
            i = j;
        }
    }
    TreeNode* build(TreeNode* root)
    {
        if(v[i] == nll)
        {
            root->left = nullptr;
            i++;
        }
        else
        {
            root->left = new TreeNode(v[i]);
            i++;
            build(root->left);
        }
        if(v[i] == nll)
        {
            root->right = nullptr;
            i++;
        }
        else
        {
            root->right = new TreeNode(v[i]);
            i++;
            build(root->right);
        }
        return root;
    }
    // Decodes your encoded data to tree.
    TreeNode* deserialize(string data) {
        if(data == "_#")
            return nullptr;
        helper(data);
        TreeNode* root = new TreeNode(v[0]);
        return build(root);
    }
};

10.15 目标和 lc494

1.简单dfs

class Solution {
public:
    int n;
    //int ans = 0;
    int findTargetSumWays(vector<int>& nums, int target) {
        n = nums.size();
        return dfs(nums, target, 0, 0);
    }
    int dfs(vector<int>& nums, int target, int curSum, int i)
    {
        if(i == n && curSum == target)
            return 1;
        if(i == n)
            return 0;
        int n1 = dfs(nums, target, curSum + nums[i], i + 1);
        int n2 = dfs(nums, target, curSum - nums[i], i + 1);
        return n1 + n2;
    }
};

2. dfs+记忆化搜索

memo记录的是key = (i, cursum), value=要求的个数

class Solution {
public:
    int n;
    //int ans = 0;
    unordered_map<string, int> memo;
    int findTargetSumWays(vector<int>& nums, int target) {
        n = nums.size();
        return dfs(nums, target, 0, 0);
    }
    int dfs(vector<int>& nums, int target, int curSum, int i)
    {
        string key = to_string(i) + "_" + to_string(curSum);
        if(memo.count(key))
            return memo[key];
        if(i == n && curSum == target)
        {
            memo[key]++;
            return memo[key];
        }
        if(i == n)
        {
            memo[key] = 0;
            return memo[key];
        }
        int n1 = dfs(nums, target, curSum + nums[i], i + 1);
        int n2 = dfs(nums, target, curSum - nums[i], i + 1);
        memo[key] = n1 + n2;
        return n1 + n2;
    }
};

3. 01背包

在记忆化的基础上变成01背包

class Solution {
public:
    int findTargetSumWays(vector<int>& nums, int target) {
        int n = nums.size();
        int sum = 0;
        for(int x: nums)
            sum += x;
        if(target > sum || target < -sum) return 0;
        vector<vector<int>> dp(n + 1, vector<int>(2 * sum + 1, 0));
        dp[0][0 + sum] = 1;
        for(int i = 1; i <= n; i++)
        {
            for(int cur = -sum; cur <= sum; cur++)
            {
                if(cur - nums[i - 1] >= -sum)
                    dp[i][cur + sum] = dp[i - 1][cur - nums[i - 1] + sum];
                if(cur + nums[i - 1] <= sum)
                    dp[i][cur + sum] += dp[i - 1][cur + nums[i - 1] + sum];
            }
        }
        return dp[n][target + sum];
    }
};

10.15 分割等和子集 lc 416

划分两个子集使得x = y,也即是找到一个子集使得x=sum/2。也就是从这些数字中选一些数使得和为sum/2。

01背包问题

class Solution {
public:
    int n;
    bool canPartition(vector<int>& nums) {
        n = nums.size();
        int sum = 0;
        for(int x: nums)
            sum += x;
        if(sum % 2) return false;
        else return findTargetSumWays(nums, sum / 2);
    }
    int findTargetSumWays(vector<int>& nums, int target)
    {
        vector<vector<bool>> dp(n + 1, vector<bool>(target + 1, false));
        for(int i = 0; i <= n; i++)
            dp[i][0] = true;
        for(int i = 1; i <= n; i++)
        {
            for(int cur = 0; cur <= target; cur++)
            {
                dp[i][cur] = dp[i - 1][cur];
                if(nums[i - 1] <= cur)
                    dp[i][cur] = dp[i][cur] || dp[i - 1][cur - nums[i - 1]];
            }
        }
        return dp[n][target];
    }
};

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-21dgU3as-1668235849934)(10_leetcode.assets/image-20221027170532069.png)]

!10.15 用栈操作构建数组 lc 1441

!10.16 可能的二分法 lc 886

10.17 完全平方数

还是01背包问题,就是从平方和中选选到和为target的最小数量

class Solution {
public:
    const int INF = 0x3f3f3f3f;
    int numSquares(int n) {
        vector<int> sq;
        for(int i = 0; i * i <= n; i++)
            sq.push_back(i * i);
        int dp[n + 1];
        memset(dp, INF, sizeof dp);
        dp[1] = 1;
        dp[0] = 0; 
        for(int i = 0; i < sq.size(); i++)
        {
            for(int j = 0; j <= n; j++)
            {
                if(sq[i] <= j)
                    dp[j] = min(dp[j], dp[j - sq[i]] + 1);
            }
        }
        return dp[n];
    }
};

10.17 零钱兑换 lc 322

完全背包问题:物品可以无限使用,要求背包装满,要求使用的数量最少。

在满足:amount=v1x1+v2x2+v3x3+…+vnxn 的条件下,求: target=min{x1+x2+x3+…xn}可以dfs将所有的组合拿出来,然后取硬币数最小。

dp[i]表示硬币和为i时的最小硬币数,然后看取不取前i个硬币,取最小即可。

class Solution {
public:
    const int INF = 0x3f3f3f3f;
    int coinChange(vector<int>& coins, int amount) {
        int n = coins.size();
        int dp[amount + 1];
        memset(dp, INF, sizeof dp);
        dp[0] = 0;
        for(int i = 0; i < n; i++)
        {
            for(int j = 0; j <= amount; j++)
            {
                if(coins[i] <= j)
                {
                    dp[j] = min(dp[j], dp[j - coins[i]] + 1);
                }
            }
        }
        if(dp[amount] == INF)
            return -1;
        else
            return dp[amount];
    }
};

!10.17 水果成篮 lc 904

!10.18 最大为 N 的数字组合 lc 902

10.18 环形链表 lc 141

快慢指针

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    bool hasCycle(ListNode *head) {
        if(head == nullptr)
            return false;
        if(head->next == nullptr)
            return false;
        ListNode* fast = head;
        ListNode* slow = head;
        while(fast != nullptr)
        {
            slow = slow->next;
            fast = fast->next;
            if(fast != nullptr)
                fast = fast->next;
            if(slow == fast)
                return true;
        }
        return false;
    }
};

10.18 环形链表|| lc 142

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode* fast = head, *slow = head;
        if(head == nullptr) return nullptr;
        if(head->next == nullptr) return nullptr;
        while(fast != nullptr)
        {
            slow = slow->next;
            fast = fast->next;
            if(fast != nullptr)
                fast = fast->next;
            if(fast == slow)
            {
                fast = head;
                while(fast != slow)
                {
                    fast = fast->next;
                    slow = slow->next;
                }
                return fast;
            }
        }
        return nullptr;
    }
};

10.18 删除链表的倒数第 N 个结点 lc 19

还是快慢指针找到倒数第n个节点然后再删除~下次再练习

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* p = head;
        if(head->next == nullptr)
            return nullptr;
        for(int i = 0; i < n; i++)
            p = p->next;
        ListNode* q = head;
        if(p == nullptr)
            return head->next;  //删掉头节点

        while(p->next != nullptr)
        {
            p = p->next;
            q = q->next;
        }
        ListNode* nx = q->next;
        q->next = nx->next; 
        return head;
    }
};

!10.19 无法吃午餐肉的同学 lc 1700

!10.19 括号的生成 lc 22

!10.19 组合总和 lc 39

回溯

class Solution {
public:
    vector<vector<int>> ans;
    vector<int> tmp;
    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
        sort(candidates.begin(), candidates.end());
        dfs(candidates, target, 0, 0);
        return ans;
    }
    void dfs(vector<int>& candidates, int target, int curSum, int i)
    {
        if(curSum == target)
        {
            ans.push_back(tmp);
            return;
        }
        if(curSum > target)
        {
            return;
        }
        for(int j = i; j < candidates.size(); j++)
        {
            tmp.push_back(candidates[j]);
            dfs(candidates, target, curSum + candidates[j], j);
            tmp.pop_back();
        }
    }
};

!10.19 组合总数 II lc 42

class Solution {
public:
    vector<vector<int>> ans;
    vector<int> tmp;
    vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
        sort(candidates.begin(), candidates.end());
        dfs(candidates, target, 0, 0);
        return ans;
    }
    void dfs(vector<int>& candidates, int target, int cur, int last)
    {
        if(cur == target)
        {
            ans.push_back(tmp);
            return;
        }
        if(cur > target)
        {
            return;
        }
        for(int i = last; i < candidates.size(); i++)
        {
            if(i > last && candidates[i] == candidates[i - 1])
                continue;
            tmp.push_back(candidates[i]);
            dfs(candidates, target, cur + candidates[i], i + 1);
            tmp.pop_back();
        }

    }
};

!10.19 电话号码的字母组合 lc 17

10.20 缺失的第一个正数 lc 41

最大的缺失的正数也不会超过nums.size()。还是和下标相关

把每个数放在下标应该在的数上,然后从0开始判断如果和下标不一样的第一个数就是缺失的第一个正数。

class Solution {
public:
    int firstMissingPositive(vector<int>& nums) {
        int n = nums.size();
        for(int i = 0; i < n; i++)
        {
            while(nums[i] > 0 && nums[i] < n && nums[i] != nums[nums[i] - 1])
                swap(nums[i], nums[nums[i] - 1]);
        }
        for(int i = 0; i < n; i++)
        {
            if(nums[i] != i + 1)
                return i + 1;
        }
        return n + 1;
    }
};

10.20 寻找重复数 lc 287

把数组看成链表,找到环的入口

class Solution {
public:
    int findDuplicate(vector<int>& nums) {
        //将数组看成链表,找到环的入口
        int slow = 0, fast = 0;
        while(1)
        {
            slow = nums[slow];
            fast = nums[nums[fast]];
            if(slow == fast)
                break;
        }
        fast = 0;
        while(slow != fast)
        {
            slow = nums[slow];
            fast = nums[fast];
        }
        return slow;
    }
};

10.20 找到所有数组中消失的数字 lc 448

就是把出现的数字和下标关联起来,将出现的数字的下标存储的数变成负数,最后是正数的就是缺失的。

class Solution {
public:
    vector<int> findDisappearedNumbers(vector<int>& nums) {
        vector<int> ans;
        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)
                ans.push_back(i + 1);
        }
        return ans;
    }
};

!10.20 第K个语法符号lc 779

!10.21 股票价格跨度 lc 901

!10.22 根据身高重建队列 lc 406

!10.22 规划兼职工作lc 1235

!10.24 除自身以外的乘积 lc 238

!10.24 和为k的子数组 lc 560

!10.24 分割数组 lc 915

!10.25 最短的桥

!10.26 任务调度器 lc 621

!10.26 和至少为k的最短子数组 lc 862

!10.28 戳气球 lc 312

!10.28 子数组的最小值之和 lc 907

10.30 LRU缓存 lc 146

哈希表+ 双向链表:最关键的就是加上一个头节点和尾节点,剩下的就仔细写仔细调试就可以了。

struct Node
{
    int key;
    int value;
    Node* next;
    Node* pre;
    Node(int k, int v)
    {
        key = k;
        value = v;
        next = nullptr;
        pre = nullptr;
    }
};
class LRUCache {
public:
    Node* head;
    Node* nail;
    int cnt = 0;
    int cap;
    unordered_map<int, Node*> hashmap;
    LRUCache(int capacity) {
        cap = capacity;
        head = new Node(-1, -1);
        nail = new Node(-1, -1);
        head->next = nail;
        head->pre = nail;
        nail->next = head;
        nail->pre = head;
    }
    
    int get(int key) {
        if(hashmap.find(key) == hashmap.end())
            return -1;
        Node* tmp = hashmap[key];
        remove(tmp);
        addFromHead(tmp);
        return tmp->value;
    }
    void remove(Node* t)
    {
        hashmap.erase(t->key);
        Node* pt = t->pre;
        Node* nt = t->next;
        pt->next = nt;
        nt->pre = pt;
        cnt--;
    }
    void addFromHead(Node* t)
    {
        hashmap[t->key] = t;
        Node* nt = head->next;
        t->next = nt;
        t->pre = head;
        head->next = t;
        nt->pre = t;
        cnt++;
    }
    void put(int key, int value) {
        if(get(key) != -1)
        {
            head->next->value = value;
            return;
        }
        if(cnt < cap)
        {
            Node* tmp = new Node(key, value);
            addFromHead(tmp);
        }
        else
        {
            Node* tmp = new Node(key, value);
            Node* nt = nail->pre;
            remove(nt);
            addFromHead(tmp);
        }
    }
};

10.30 字母大小写全排列 lc 784

回溯

class Solution {
public:
    vector<string> ans;
    string tmp;
    vector<string> letterCasePermutation(string s) {
        dfs(s, 0);
        return ans;
    }
    void dfs(string s, int i)
    {
        if(i == s.size())
        {
            ans.push_back(tmp);
            return;
        }
        if(s[i] >= '0' && s[i] <= '9')
        {
            tmp += s[i];
            dfs(s, i + 1);
            tmp.pop_back();
        }
        else if(s[i] >= 'a' && s[i] <= 'z')
        {
            tmp += s[i];
            dfs(s, i + 1);
            tmp.pop_back();
            tmp += (s[i] - 32);
            dfs(s, i + 1);
            tmp.pop_back();
        }
        else
        {
            tmp += s[i];
            dfs(s, i + 1);
            tmp.pop_back();
            tmp += (s[i] + 32);
            dfs(s, i + 1);
            tmp.pop_back();
        }
    }
};

10.30 最小栈 lc 155

两个栈辅助的

class MinStack {
public:
    stack<int> stk;
    stack<int> minstack;
    MinStack() {

    }
    
    void push(int val) {
        stk.push(val);
        if(minstack.empty() || val <= minstack.top())
            minstack.push(val);
    }
    
    void pop() {
        int x = stk.top();
        cout << x << endl;
        stk.pop();
        if(minstack.size() && x == minstack.top())
            minstack.pop();
    }
    
    int top() {
        return stk.top();
    }
    
    int getMin() {
        cout << minstack.top() << endl;
        return minstack.top();
    }
};

链表解决的:头插法,每个节点中记录栈顶当前值和当前值作为栈顶时的最小值。

struct node
{
    int val;
    int min;
    node* next;
    node(int x, int y)
    {
        val = x;
        min = y;
        next = nullptr;
    }
};
class MinStack {
public:
    node* head;
    MinStack() {
        head = nullptr;
    }
    
    void push(int val) {
        if(head == nullptr)
            head = new node(val, val);
        else
        {
            int m = val <= head->min? val: head->min;
            node* tmp = new node(val, m);
            tmp->next = head;
            head = tmp; 
        }
    }
    
    void pop() {
        head = head->next;
    }
    
    int top() {
        return head->val;
    }
    
    int getMin() {
        return head->min;
    }
};

10.31 滑动窗口的最大值 lc 239

模拟滑动窗口不行因为如果排出最大值要重新遍历找最大值,会超时

因此,选择双向队列维护一个单调递减的队列,当删掉的值==左边最大值时,将其删掉.当加入的值大于队尾的值时,删掉队尾维持递减队列.

class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        vector<int> ans;
        int n = nums.size();
        deque<int> q;
        int l = 0, r = k - 1;
        for(int i = l; i <= r; i++)
        {
            while(q.size() && nums[i] > q.back())
                q.pop_back();
            if(!q.size() || nums[i] <= q.back())
                q.push_back(nums[i]);
        }
        ans.push_back(q.front());
        while(r + 1 < n)
        {
            if(q.size() && nums[l] == q.front())
                q.pop_front();

            while(q.size() && nums[r + 1] > q.back())
                q.pop_back();
            q.push_back(nums[r + 1]);
            ans.push_back(q.front());
            l++;
            r++;
        }
        return ans;
    }
};

10.31 神奇字符串 lc481

模拟题目即可,小技巧 1^3 = 2 2^3 = 1

class Solution {
public:
    int magicalString(int n) {
        int x1 = 3, x2 = 3;  //x1是总的字符串数量,x2是生成到哪一个
        vector<int> s(4, 0);
        s[1] = 1; s[2] = 2; s[3] = 2;
        int cnt = 1, f = 1;;
        while(x1 < n)
        {
            int t = 0;
            if(s[x2] == 1)
            {
                s.push_back(f);
                cnt += (f == 1);
                x1++;
            }
            else
            {
                s.push_back(f);
                s.push_back(f);
                x1 += 2;
                cnt += (f == 1) * 2;
            }
            f = f ^ 3;
            x2++;
        } 
        if(x1 > n && s[x1] == 1) cnt--;
        return cnt;
    }
};

10.31 课程表 lc 207

气死我了,一个拓扑排序写了这么久…

const int N = 5010;
int h[N], e[N], ne[N], idx;
void add(int a, int b)
{
    e[idx] = b; ne[idx] = h[a]; h[a] = idx++;
}
class Solution {
public:
    bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
        //if(prerequisites.size() == 1 && prerequisites[0][0] != p[])
        idx = 0;
        int cnt = 0;
        int inorder[numCourses];
        memset(inorder, 0, sizeof inorder);
        memset(h, -1, sizeof h);
        for(auto x: prerequisites)
        {
            if(x[0] == x[1])
                return false;
            add(x[0], x[1]);
            inorder[x[1]]++;
        }
        queue<int> q;
        int f = 0;
        for(int i = 0; i < numCourses; i++)
        {
            if(inorder[i] == 0)
            {
                q.push(i);
                inorder[i] = -1;
            }
        }
        while(q.size())
        {
            int b = q.front();
                q.pop();
                cnt++;
                for(int k = h[b]; k != -1; k = ne[k])
                {
                    int a = e[k];
                    inorder[a]--;
                    if(!inorder[a])
                        q.push(a);
                }
        }
        if(cnt < numCourses)
            return false;
        else
            return true;
        
    }
};

组合题目

1. 与下标相关的

2. 前缀和

3. 01背包

4. 单调栈

一些有的没的

  1. 字符串转int atoi()但是还需要从string 转到char : s.c_str()

    即 int x = atoi(s.c_str());

    int转string : string s = to_string(x);

    1. priority_queue

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/5251.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Redis系列:Redis主从、哨兵、集群介绍

本篇内容包括&#xff1a;Redis 主从架构、Redis 哨兵架构、Redis 集群架构 的介绍等内容&#xff5e; 文章目录一、Redis 主从架构1、Redis 主从架构2、主从架构原理二、Redis 哨兵模式1、Redis 哨兵模式2、Redis 哨兵模式工作过程三、Redis 集群模式1、Redis 集群模式2、Redi…

【树莓派不吃灰】基础篇⑲ 搭建usb摄像头MJPG-streamer图片流监控,支持远程视频监控访问

目录1. 前言2. 识别摄像头3. MJPG-streamer方案3.1 什么是 MJPG&#xff1f;3.2 MJPG 的优点&#xff1f;3.2 MJPG 的缺点&#xff1f;4. 搭建usb摄像头监控4.1 开启树莓派摄像头开关4.2 查看设备文件4.3 安装必要的库4.4 下载 mjpg-streamer 安装文件4.5 切换到 /mjpg-streame…

基于51单片机的温度甲烷监测报警串口上报proteus仿真原理图PCB

功能介绍&#xff1a; 0.本系统采用STC89C52作为单片机 1.LCD1602液晶实时显示当前温度和甲烷浓度 2.超过甲烷浓度阈值&#xff0c;蜂鸣器报警 3.按键可更改甲烷浓度阈值上限和启动/暂停检测 4.020%浓度&#xff0c;绿色LED点亮 20%~阈值上限&#xff0c;黄色LED点亮&#xff0…

C#操作modbus

modbus使用范围广泛&#xff0c;广泛应用于各类仪表&#xff0c;PLC等。 modbus的好处是免费&#xff0c;属于应用层协议&#xff0c;底层硬件基于485/以太网。 modbus协议本质还是自定义协议。 modbus调试软件&#xff1a; mthings: modbuspoll: 主站/从站&#xff0c;客…

前端静态页面基本开发思路(一)

有不少刚入门前端的同学经常问我前端布局的问题&#xff0c;总是跟我说在面对学校布置的作业或者想自己搭建博客的时候不知道怎么下手&#xff0c;不知道怎么去写静态的页面&#xff0c;每当我解决了一个又一个同学的问题的时候&#xff0c;又有新的同学来问&#xff0c;故思来…

nginx 配置防盗链(了解)

一 防盗链 1.1 防盗链概念 网站上页面的一些静态资源&#xff0c;不想让本站点的静态资源被他人盗取访问。使用nginx判断请求连接的头部refer中是否含有内容以及合法性来进行处理。 referer表示第二次资源的来源地址 1.2 配置规则 valiad_referers none|blocked|server_na…

Spring--IOC基于XML管理bean

IOC容器 IOC思想 IOC&#xff1a;Inversion of Control 即反转控制 获取资源的传统方式 自己做饭&#xff1a;买菜、洗菜、择菜、改刀、炒菜&#xff0c;全过程参与&#xff0c;费时费力&#xff0c;必须清楚了解资源创建整个过程中的全部细节且熟练掌握。 在应用程序中的组件…

Antd表格性能优化

今天来分享一个实际项目的性能优化的内容。 文章目录一、背景介绍二、性能问题原因及解决方案一、背景介绍 国内React项目大多数人选择配套的UI库的时候都会选择Antd。如果是非常简单的页面用Antd的话其实是完全没问题的&#xff0c;性能感觉不到什么瓶颈&#xff0c;样式也还…

计算机网络

目录 介绍 组成部分 工作方式 功能组成 网络范围分类 传输技术&#xff1a; 总结 标准化工作 RFC文档的作用&#xff1a; 速率&#xff0c;带宽 有容量和速率的区别 带宽 吞吐量 时延&#xff0c;时延带宽积 1.发送时延&#xff1a; 2.传播时延&#xff1a; ​编辑 3.…

Vant组件库 引入 阿里矢量图 添加自己喜欢的 ICON

&#x1f4c3;目录跳转一.矢量图下载&#x1f4a8;使用CDN方式&#x1f389;下载本地&#xff08;推荐&#xff09;二.Vant引入Icon&#x1f5fa;️&#x1f383; 使用方式&#x1f680; 运行效果&#xff1a;一.矢量图下载 &#x1f4a8;使用CDN方式 当然你也可以使用官方的C…

【编程题】【Scratch三级】2021.12 分身术

分身术 1. 准备工作 (1)删除小猫角色、添加角色“Monkey”,Money位于舞台的中心; (2)添加背景Light; (3)新建变量“编号”。 2. 功能实现 (1)程序开始时,Monkey说:“我会分身术!变!!!”2秒; (2)每隔2秒克隆出一个位置随机、大小随机、颜色随机的Monke…

python easygui修改窗口位置

EasyGui是一个十分简单的Python图形界面库&#xff0c;支持窗口文本显示、图片显示、按钮、文本框、选项栏、文件选择等等必要的组件且操作十分简单。但也因如此&#xff0c;导致EasyGui甚至不能手动调整窗口位置、按钮位置、名字等&#xff0c;因为EasyGui是基于Tkinter编写的…

VMware三种网络模式详解

VMware三种网络模式 linux重启网络服务命令&#xff1a; service network restart 一、桥接模式 原理&#xff1a;VMware和宿主机&#xff0c;处于同一网段、两者地位平等。&#xff08;无需虚拟网卡&#xff09; 1.1、使用方法 虚拟网络编辑器 虚拟机设置-适配器 上面两…

<Linux> 编译器与调试器—gcc/g++/gdb 的使用

< Linux > 编译器与调试器—gcc/g/gdb 的使用 文章目录< Linux > 编译器与调试器—gcc/g/gdb 的使用一、Linux编译器 - gcc/g 使用1. 编译程序的四个过程背景知识预处理编译汇编链接2. 链接方式与函数库2.1 动态链接与静态链接2.2.函数库2.3.动态库与静态库3. gcc/…

干货分享:谷歌主动搜索开发客户的万能公式

大家在用谷歌(Google)开发是不是也有以下常见问题&#xff1a; 关键词不准&#xff0c;搜索到的都是零售商&#xff0c;B2C平台搜索到的客户太大&#xff0c;已经被开发多次&#xff0c;开发信不回复搜索到的客户找不到邮箱搜索到的客户与工厂不匹配&#xff0c;无法合作 其实…

车路协同 智能路侧设备网络安全接入技术要求

1 范围 本文件包含智能路侧设备网络安全接入技术要求&#xff0c;包括智能路侧设备连接要求、接入要求、证书管理要求。 本文件适用于智能路侧设备网络安全接入的设计与开发。 2 规范性引用文件 下列文件中的内容通过文中的规范性引用而构成本文件必不可少的条款。其中&…

Simulink永磁同步电机控制仿真:过调制及电流重构

在一些高功率密度的应用场景中&#xff0c;追求极致的电压利用率&#xff0c;这个时候要用到过调制技术&#xff1b;当svpwm工作在过调制区域时&#xff0c;逆变电桥会在一个基波周期内多次达到100%占空比&#xff0c;且较多时间处于较高的占空比&#xff0c;这个时候下桥臂电流…

数据结构系列学习(七) - 链栈(Chain_Stack)

目录 引言&#xff1a; 学习&#xff1a; 代码实现&#xff1a; 头文件&#xff08;Chain_Stack.h&#xff09;&#xff1a; 设置链栈中的元素范型&#xff1a; 链栈的结构体设计&#xff1a; 所有功能函数的声明&#xff1a; 源文件&#xff08;Chain_Stack.cpp&#…

性能测试场景设计之 阶梯性能场景(负载测试场景)

「负载测试&#xff1a;」 逐步增加并发用户数。看服务器的最大拐点区间在哪里。再缩小拐点区间&#xff0c;找出最大并发用户数。 使用方式&#xff1a; 安装 jpgc插件 添加线程组 每次递增10个并发 This group will start&#xff1a;给定当前负载的并发用户数First, wait …

机器学习-集成算法

文章目录集成算法1. 定义2. 具体模型2.1. Bagging2.2. Boosting2.3. Stacking3. 随机森林3.1. 树模型结构3.2. 随机森林的优点3.3. 分类与回归问题3.4. 树模型个数问题3.5. 参数问题(特征重要性)3.6. 可视化展示问题4. 集成基本思想4.1. 硬投票策略步骤4.2. 软投票策略步骤5. B…