Leetcode 400刷题计划

博主又又又回来了,申请almost done,开始leetcode400刷题计划了,打算前期每天5-10题吧,最近耍了一天,感觉太久没写代码了,A率下降了好多😭,开始回炉重造。

2023.10.7&2023.10.8
Easy: map用法
Medium:ListNode用法
Hard:两个指针比较移动,注意边界和奇偶讨论
Medium:寻找每行坐标规律
Medium:用long, 学到INT_MAX和INT_MIN用法
Medium:特判比较多的快读
Medium: 单调队列上二分查找,对于左边柱子确定,比他高的肯定找最远的;对于右边第一个比他矮的(下降队列里找到的),后面的柱子则都需要比较
Medium:不同位数同个原理,switch搞定
Medium:枚举i, j,k用map查找,注意去重(排序组成字符串+map),最后去重TLE
Medium:枚举i, j, 二分最小差值
Medium
Medium:#左>#右搜索
Hard:priority_queue一用就水题
Medium: ListNode画一画
Medium
 
2023.11.20
Hard:这题是DP,原来没想到,dp[i][j], i,j对应两个字符串位置,经典题型
Hard:找一下操作的规律,多画画可出
Hard:sliding window,好题
Hard:栈模拟,也是一个sliding winow, 括号长度pos - st[tp - 1]
Hard:基础的搜索,不用剪枝
Medium:39裸题,这题必须pair纪录cnt, 一层一层调用爆栈空间。
Hard:好题(O(n)Time O(1)Space),核心把每个数移动到下标和他值一样的题,交换。
Hard:单调栈
Medium
Hard:又是DP,正则表达式看来就是DP了
Medium
Medium:先对角线翻转,在横着翻转
Medium:先把每个字符串排序,然后比较
Medium:快速幂
 
2023.11.21
Medium:dp[n]表示以n为结尾的和最大子序列
Medium:dp[i]表示跳到i所需最少步数
Medium:排序+小贪心
Medium:dp[i][j]表示走到(i,j)的方案数,62,64同类型题
Hard:纯模拟,难度day2T1
Hard:纯模拟,难度day2T1
Medium
 
2023.11.22
Medium: dp[i][j]表示匹配到word1[i],word[j]所需最少步数,注意处理空串
Medium:O(1)Space:将(i,j)的0移动到(i,0),(0,j),单独处理0行0列的0,注意原来0行0列是否有0
Medium:O(1)Space有点意思:两个指针维护已排序中1,2首次出现的位置
Hard:比30harder一点的sliding window
 
2024.04.08
Medium:简单dfs
Medium: 数位dp枚举
Medium:线性扫描找到要去除的元素打标记(改为极大值),后面双指针,将被标记元素与下一个最近的未标记元素swap,注意末尾特判
Medium:如果没有重复的,可以二分找到rotate的位置,然后前部分下标平移继续二分找数,又重复复杂度就会达到O(N)
Medium:考察代码细节,考虑开头,结尾,连着重复情况
Hard:好题,找一个数组(每个数代表高度)中最大的长方形

 题解:对每个位置i, 考虑i是最低情况时可以组成的最大长方形,那要预处理i左边和右边不能到达的位置(比i还小),复杂度O(N)

        if(heights[i] > heights[i - 1]){
                lf[i] = i-1;
            }               
            else {
                int t = lf[i-1];
                while(t != -1 && heights[i] <= heights[t]) {
                    t = lf[t];
                }
                lf[i] = t;
            }    
View Code

 

 
2024.06.05
今天开始按照题型刷了,先做1D-DP
Easy:水题,dp[i] = dp[i-1] + dp[i-2]
Easy:水题,dp[i] = min(dp[i-1] + cost[i-1], dp[i-2] + cost[i-2])
Medium:水题,for(int i = 1; i < nums.size(); i++) dp[i + 1] = max(dp[i], dp[i - 1] + nums[i])
Medium:在198的基础上改成了环,首尾不能同时选,更改dp状态dp[n][0/1]: 0表示考虑到n时第一个房子没选,1表示考虑到n时第一个房子选了,处理一下边界即可
5. Longest Palindromic Substring
Medium: dp优化成O(N^2), 性质:aba是回文那么xabax也是回文,所以dp[i][[j] = dp[i+1][j-1] && (s[i]==s[j]),简化空间,我们考虑成一维,
dp[i]表示以i结尾长度为k的最长回文,k可以用枚举省略掉,那么dp[i] = dp[i-1] && (s[i]==s[i-k+1]), 注意dp[i-1]是长度为k-2的情况下的dp,
所以参照213,我们用dp[i][0/1]来表示长度k是奇数/偶数下最长回文,注意i是结尾,要倒序更新(类似背包问题),
class Solution {
public:
    string longestPalindrome(string s) {
        string ans;
        bool dp[1005][2];
        ans = s[0];
        int n = s.length();
        // length = 1
        for(int i = 0; i < n; i++) dp[i][1] = dp[i][0] = 1;
        
        // length = k, longest one
        for(int k = 2; k <= n; k++){
            int now = k % 2;
            for(int ed = n - 1; ed; ed--) {
                if (ed - k + 1 < 0) break;
                bool fg = dp[ed - 1][now] && (s[ed] == s[ed - k + 1]);
                if (fg) {
                    dp[ed][now] = 1;
                    ans = s.substr(ed - k + 1, k);
                }
                else {
                    dp[ed][now] = 0;
                }
                // printf("%d %d %d %d %c %c\n", k, ed, dp[ed-1][now], dp[ed][now], s[ed], s[ed-k+1]);

            }
        
        }
            

        
        return ans;
    }
};
View Code

 

2024.06.06

91. Decode Ways

Medium::水题, T(N), S(N)

322. Coin Change

Medium:完全背包,T(N), S(N^2)

152. Maximum Product Subarray
Medium: 用sliding window,T(N), S(N),两个状态:min_dp[i]/max_dp[i]表示以i结尾(必须选中i)的最小/最大乘积,min_dp[i] = min(
min_dp[i-1] * nums[i], max_dp[i-1] * nums[i], nums[i])

139. Word Break

Medium:水题, T(NM), S(N)

647. Palindromic Substrings

Medium:利用第5题dp,每个dp为true则ans+1,T(N^2), S(N)

1851. Minimum Interval to Include Each Query 

 

 

2024.7.7

300. Longest Increasing Subsequence

Medium:最长单调子序列,T(NlogN), S(N)

Medium:Coin Change和变成一半版本,T(N*SUM), S(SUM)

1143. Longest Common Subsequence

Medium:最长公共子序列,水题,T(N^2), S(N^2)

518. Coin Change II
Medium:组成钱币方案数,完全背包,先枚举物品再枚举容量(防止方案重复),T(N^2), S(N^2)
Medium: 每天四种状态:dp[i][0/1/2/3]: 0: buy 1: sell 2: rest w stock 3. rest w/o stock,按逻辑转移,T(N), S(N)

 

 2024.06.12

53. Maximum Subarray

Medium: 简单DP,T(N), S(N)

55. Jump Game

Medium: 水题,T(N), S(1)

45. Jump Game II

Medium: 简单DP,T(N), S(N)

371. Sum of Two Integers
Easy: 不用加法实现加法,二进制模拟carry,模拟题, T(1), S(1)
class Solution {
public:
    int getSum(int a, int b) {
        int carry = (a & b) << 1, rest = a ^ b;
        int ans = 0;
        while(carry & rest) {
            int tmp = carry;
            carry &= rest;
            carry <<= 1;
            rest ^= tmp;
        }
        return carry | rest;

    }
};
View Code
190. Reverse Bits
Easy: for loop; T(1), S(1)
Easy: left shift property, 仿照素数筛; T(N), S(N)
Update: vincent's: reduce the effect of LSB
def countBits(n: int) -> list[int]:
    dp = [0] * (n + 1)
    offset = 1

    for i in range(1, n+1):
        if offset * 2 == i:
            offset = i
        dp[i] = 1 + dp[i - offset]
        print(i, offset, dp[i])
    return dp
View Code
Easy: Xor, T(N), S(1)
 
 2024.06.13
Medium: 贪心,最小区间覆盖,T(NlogN), S(N)
Medium:贪心,维护左括号和*栈记录位置,优先匹配左括号,后面检验剩余左括号,*位置必须大于左括号,T(N), S(N)
Medium: 维护一个gas-cost数组,从0向右加,一旦和<0, 向左(结尾)延伸至和>=0, 看是否走完一圈,T(N), S(N)
 

2024.06.14 & 2024.0615

48. Rotate Image

Medium:旋转矩阵S(1)要求,for loop模拟位置变换, T(N^2)

54. Spiral Matrix

Medium:建一个方向数组和边界检查,细节题,S(1), T(NM) 

73. Set Matrix Zeroes

Medium:笔试原题, S(1), T(NM), We can use the first cell of every row and column as a flag. This flag would determine whether a row or column has been set to zero. 注意0行0列特判

202. Happy Number

Easy: set找重复,S(N), T(N)

50. Pow(x, n)

Easy: 快速幂,S(1), T(logN)

66. Plus One

Easy: 水题

43. Multiply Strings

Medium: 水题

2013. Detect Squares

Medium:模拟,用map记录位置点的数量

 

2024.06.16 

97. Interleaving String

Medium: 本题核心,所谓的abs(n-m) <= 1, 是陷阱,其实就是看s1,s2里的字母按顺序交错是否可以组成s3, 我们可以一直按单个单个字母填(有需要当他自动合并),就是典型DP,
dp[i][j]表示取s1长度i, s2长度j,能否构成s3长度i+j,转移方程dp[i][j] |= (dp[i-1][j] && (s1[i] == s3[i+j])); dp[i][j] |= (dp[i][j-1] && (s2[j] == s3[i+j])); S(N^2) T(N^2)
Medium: 做过的经典DP,一位一位计算,s1增加相当于s2减少,S(N^2) T(N^2)
Hard: DP[i][j]表示s1[:i]是否可以含有子序列s2[:j],这题学到一点,说最终答案32bit,中间如果overflow,那么不会贡献给最终答案,S(N^2) T(N^2)
if(i) dp[i][j] += dp[i - 1][j];
if(i && j && s[i] == t[j] && dp[i - 1][j - 1] <= LLONG_MAX - dp[i][j]) 
       dp[i][j] += dp[i - 1][j - 1];
View Code

312. Burst Balloons

Hard: 区间DP,DP[i][j]表示扎爆i到j之间气球最大收益,S(N^2) T(N^3)

class Solution {
public:
    int dp[305][305];
    int maxCoins(vector<int>& nums) {
        int n = nums.size();
        nums.insert(nums.begin(), 1);
        nums.push_back(1);
        for(int len = 1; len <= n; len++)
            for(int i = 1; i <= n; i++) {
                int j = i + len - 1;
                if(j > n) break;
                for(int k = i; k <= j; k++){
                    int tmp = nums[k] * nums[i - 1] * nums[j + 1];
                    if(k > i) tmp += dp[i][k - 1];
                    if(k < j) tmp += dp[k + 1][j];
                    dp[i][j] = max(dp[i][j], tmp);
                }
                // printf("%d %d %d\n", i, j, dp[i][j]);
            }
        return dp[1][n];        
    }
};
View Code

10. Regular Expression Matching

Hard: 好题, real hard, S(N^2) T(N^2)

class Solution {
public:
    bool isMatch(string s, string p) {
        bool dp[25][25];
        memset(dp, 0, sizeof(dp));
        dp[0][0] = 1;
        for(int i = 0; i <= s.size(); i++)
            for(int j = 1; j <= p.size(); j++){
                if(p[j - 1] == '*') {
                    dp[i][j] = dp[i][j - 2] | ((i > 0) && dp[i-1][j] & (s[i - 1] == p[j - 2] || p[j - 2] == '.'));
                    
                }
                else {
                    dp[i][j] = (i > 0) && (dp[i - 1][j - 1] & (s[i - 1] == p[j - 1] | p[j - 1] == '.'));
                }
                cout<<i<<" "<<j<<" "<<dp[i][j]<<endl;
            }
        return dp[s.size()][p.size()];
    }
};
View Code

329. Longest Increasing Path in a Matrix

Hard: 四个方向都可以拓展,记忆化搜索,T(N^2), S(N^2)

class Solution {
public:
    int dp[205][205];
    int dir[4][2] = {{1,0}, {0, 1}, {-1,0},{0,-1}};
    int dfs(int x, int y, int n, int m, vector<vector<int>>& matrix){
        if(dp[x][y]) return dp[x][y];
        dp[x][y] = 1;
        int tmp = 0;
        for(int k = 0; k < 4; k++) {
            int i = x + dir[k][0], j = y + dir[k][1];
            if(i >= 0 && j >= 0 && i < n && j < m && matrix[i][j] < matrix[x][y])
                tmp = max(tmp, dfs(i, j, n, m, matrix));
        }
        dp[x][y] += tmp;
        return dp[x][y];
    }
    int longestIncreasingPath(vector<vector<int>>& matrix) {
        int n = matrix.size(), m = matrix[0].size();
        int ret = 0;
        for(int i = 0; i < n; i++)
            for(int j = 0; j < m; j++)
                if(!dp[i][j]) {
                    ret = max(ret, dfs(i, j, n, m, matrix));
                }
        return ret;
    }
};
View Code

 

2024.06.17

295. Find Median from Data Stream (H) TlogN, SN,好题

维护一个大根堆和一个小根堆,保证两个堆大小相差不超过1,小根堆堆顶大于大根堆堆顶,中位数看堆顶即可

class MedianFinder:
    import heapq
    def __init__(self):
        self.max_h = []
        self.min_h = []
        self.n1, self.n2 = 0, 0

    def addNum(self, num: int) -> None:
        if self.n1 <= self.n2:
            if self.n2 and num > self.min_h[0]:
                x = heapq.heappushpop(self.min_h, num)
                heapq.heappush(self.max_h, -x)
            else:
                heapq.heappush(self.max_h, -num)
            self.n1 += 1
        else:
            if self.n1 and num < -self.max_h[0]:
                x = heapq.heappushpop(self.max_h, -num)
                heapq.heappush(self.min_h, -x)
            else:
                heapq.heappush(self.min_h, num)
            self.n2 += 1



    def findMedian(self) -> float:
        if self.n1 > self.n2:
            return -self.max_h[0]
        return (-self.max_h[0] + self.min_h[0]) / 2


# Your MedianFinder object will be instantiated and called as such:
# obj = MedianFinder()
# obj.addNum(num)
# param_2 = obj.findMedian()
View Code

621. Task Scheduler (M)TN, SN,好题

额外维护一个队列储存元素到期时间(FIFO),到期加入优先队列

class Solution {
public:
    int cnt[26];


    int leastInterval(vector<char>& tasks, int n) {
        struct fr{
            int id, cnt, time;
            bool operator < (const fr &a)const{
                return a.cnt == cnt ? a.id < id : a.cnt > cnt;
            }
        };
        priority_queue<fr> q;
        queue<fr> sq;

        for(int i = 0; i < tasks.size(); i++)
            cnt[tasks[i] - 'A']++;
        for(int i = 0; i < 26; i++)
            if(cnt[i]) {q.push((fr){i, cnt[i], -n-1});} 
        int pos = 0;
        while(!q.empty() || !sq.empty()) {
            while(!sq.empty() && sq.front().time == pos) {
                q.push(sq.front());
                sq.pop();
            }
            if(!q.empty()) {
                fr now = q.top();
                cout<<now.id<<endl;
                q.pop();
                now.cnt--;
                if(now.cnt) {
                    now.time = pos + n + 1;
                    sq.push(now);
                }
            } 
            
            pos++;
        }
        return pos;
    }
};
View Code

355. Design Twitter (M) 纯模拟

class Twitter {
public:
    int time;
    struct data{
        int tid, idx, pid;
        bool operator < (const data &a) const {
            return idx < a.idx;
        }
    };
    unordered_map <int, priority_queue<data> > qs;
    unordered_map <int, set<int> > fs;
    Twitter() {
        time = 0;
    }
    
    void postTweet(int userId, int tweetId) {
        if(qs.find(userId) == qs.end()) {
            priority_queue<data> q;
            qs[userId] = q;
        }
        follow(userId, userId);
        qs[userId].push((data){tweetId, ++time, userId});
    }
    
    vector<int> getNewsFeed(int userId) {
        queue<data> tmp;
        vector<int> ans;
        for(int i = 0; i < 10; i++) {
            data now = (data) {-1, 0, -1};
            for(auto ppl: fs[userId])
                if(!qs[ppl].empty()){
                    data tw = qs[ppl].top();
                    if(tw.idx > now.idx) now = tw;
                }
            if(now.tid == -1) break;
            tmp.push(now);
            ans.push_back(now.tid);
            qs[now.pid].pop();
        }
        while(!tmp.empty()) {
            data a = tmp.front();
            tmp.pop();
            qs[a.pid].push(a);
        }
        return ans;
    }
    
    void follow(int followerId, int followeeId) {
        if(fs.find(followerId) == fs.end()) {
            set <int> f;
            fs[followerId] = f;
        }
        fs[followerId].insert(followeeId);
    }
    
    void unfollow(int followerId, int followeeId) {
        fs[followerId].erase(followeeId);
    }
};
View Code

 

2024.06.28

155. Min Stack:(M) T1, SN

维护一个递减栈,其余元素放另一个栈,那么递减栈栈顶一定最小,POP的时候注意顺序

class MinStack:

    def __init__(self):
        self.min_stk = []
        self.other_stk = []

    def push(self, val: int) -> None:
        if not self.min_stk or self.min_stk[-1][0] >= val:
            self.min_stk.append([val, 0])
        else:
            self.min_stk[-1][1] += 1
            self.other_stk.append(val)

    def pop(self) -> None:
        if self.min_stk[-1][1]:
            self.other_stk.pop()
            self.min_stk[-1][1] -= 1
        else:
            self.min_stk.pop()

    def top(self) -> int:
        if self.min_stk[-1][1]:
            return self.other_stk[-1]
        else:
            return self.min_stk[-1][0]
    def getMin(self) -> int:
        return self.min_stk[-1][0]
View Code

739. Daily Temperatures (M) TN, SN

class Solution:
    def dailyTemperatures(self, temperatures: List[int]) -> List[int]:
        ret = [0] * len(temperatures)
        ans = []
        for i, x in enumerate(temperatures):
            tmp = 1
            while ans and x > ans[-1][0]:
                ret[ans[-1][2]] = tmp
                tmp += ans[-1][1]
                ans.pop()
            ans.append([x, tmp, i])
        tmp = 1 
        return ret
        
View Code

853. Car Fleet (M), TNlogN, SN

class Solution:
    def carFleet(self, target: int, position: List[int], speed: List[int]) -> int:
        node = []
        n = len(position)
        for i in range(n):
            node.append([position[i], speed[i]])
        node = sorted(node)
        # print(node)
        stk = []
        for i in range(n):
            while stk:
                if stk[-1][1] <= node[i][1]:
                    break
                t = (node[i][0] - stk[-1][0]) / (stk[-1][1] - node[i][1])
                if node[i][0] + t * node[i][1] <= target:
                    stk.pop()
                else:
                    break
            stk.append(node[i])
        return len(stk)
            
View Code

84. Largest Rectangle in Histogram (H)好题,经典题 TN, SN

找一列竖条中组成的最大长方形,维护一个递增栈,出栈时更新宽度贡献

class Solution:
    def largestRectangleArea(self, heights: List[int]) -> int:
        stk = []
        ans = 0
        for x in heights:
            if not stk or x > stk[-1][0]:
                stk.append([x, 1])
            else:
                tmp = 0
                while stk and x <= stk[-1][0]:
                    stk[-1][1] += tmp
                    ans = max(ans, stk[-1][0] * stk[-1][1])
                    tmp = stk[-1][1]
                    # print(ans, stk[-1][0], stk[-1][1])
                    stk.pop()
                stk.append([x, tmp+1])
        tmp = 0
        while stk:
            stk[-1][1] += tmp

            ans = max(ans, stk[-1][0] * stk[-1][1])
            # print(ans, stk[-1][0], stk[-1][1])
            tmp = stk[-1][1]
            stk.pop()

        return ans
View Code

150. Evaluate Reverse Polish Notation M, TN,SN, 逆波兰式

 

2024.06.29

153. Find Minimum in Rotated Sorted Array M, TlogN, S1

class Solution:
    def findMin(self, nums: List[int]) -> int:
        
        lf, rg = 0, len(nums) - 1
        if nums[0] < nums[rg]:
            return nums[0]
        while lf < rg:
            mid = (lf + rg) // 2
            if nums[mid] >= nums[lf]:
                if nums[mid + 1] < nums[lf]:
                    lf = mid + 1
                    break
                lf = mid + 1
            else:
                rg = mid
        

        return nums[lf]
View Code

33. Search in Rotated Sorted Array M, TlogN, S1

class Solution:
    def search(self, nums: List[int], target: int) -> int:
        lf, rg = 0, len(nums) - 1
        n = len(nums)
        idx = 0
        if nums[0] > nums[rg]:
            while lf < rg:
                mid = (lf + rg) // 2
                if nums[mid] >= nums[lf]:
                    if nums[mid + 1] < nums[lf]:
                        lf = mid + 1
                        break
                    lf = mid + 1
                else:
                    rg = mid
            idx = lf
        n = len(nums)
        L, R = 0, n - 1
        # print(idx)
        while L <= R:
            mid = (L + R) // 2
            mm = (mid + idx) % n 
            # print(L, R, mm)
            if nums[mm] == target:
                return mm
            elif nums[mm] < target:
                L = mid + 1
            else:
                R = mid - 1
        return -1
        
View Code

435. Non-overlapping Intervals M, TNlogN, S1, 好题,贪心

class Solution:
    def eraseOverlapIntervals(self, intervals: List[List[int]]) -> int:
        array = sorted(intervals, key=lambda x: (x[0], -x[1]))
        i, n = 0, len(intervals)
        # print(array)
        i = 0
        while i < n - 1:
            while i < n - 1 and array[i][1] > array[i+1][0]:
                if array[i][1] > array[i+1][1]:
                    array.pop(i)
                else:
                    array.pop(i+1)
                n -= 1
            i += 1
            # print(i, array)
        return len(intervals) - len(array)
View Code

1851. Minimum Interval to Include Each Query H, TNlogN, SN, 好题

一个优先队列的滑动窗口问题

class Solution:
    def minInterval(self, intervals: List[List[int]], queries: List[int]) -> List[int]:
        ql = [[queries[i], i] for i in range(len(queries))]
        ql.sort()
        intervals.sort()
        idx = 0
        pq = []
        ret = [-1] * len(ql)
        # print(ql)
        # print(intervals)
        for q in ql:
            while idx < len(intervals) and intervals[idx][0] <= q[0]:
                heappush(pq, (intervals[idx][1] - intervals[idx][0] + 1, intervals[idx][1]))
                idx += 1
            # print(q, pq)
            while pq and pq[0][1] < q[0]:
                heappop(pq)
            if pq:
                ret[q[1]] = pq[0][0]
        return ret
        
View Code

 

2024.06.30

167. Two Sum II - Input Array Is Sorted M, TN, S1, 双指针

11. Container With Most Water M, TN, S1, 双指针

class Solution:
    def maxArea(self, height: List[int]) -> int:
        i, j = 0, len(height) - 1
        ans = 0
        while i < j:
            ans = max(ans, (j-i)*min(height[i], height[j]))
            if height[i] < height[j]:
                i += 1
            else:
                j -= 1
        return ans
View Code

42. Trapping Rain Water H, TN, SN,单调栈,好题

class Solution {
public:
    int trap(vector<int>& height) {
        int stk[20005], tp = 0;
        int sum = 0;
        for(int i = 0; i < height.size(); i++){
            if(!tp || height[i] < height[stk[tp]]) stk[++tp] = i;
            else {
                while(tp && height[stk[tp]] < height[i]){
                    int li = min(height[stk[tp-1]], height[i]);
                    if(li > height[stk[tp]])
                        sum += (li - height[stk[tp]]) * (i - stk[tp-1] - 1);
                    tp--;
                    // cout<<i<<" "<<li<<" "<<stk[tp]<<" "<<sum<<endl;
                }
                stk[++tp] = i;
            }
        }
        return sum;
    }
};
View Code

15. 3Sum M, TN^2, S1, 双指针(... slow)

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        nums = sorted(nums)
        n = len(nums) 
        ans = []
        # print(nums)
        for i in range(n):
            j = i + 1
            k = n - 1
            while j < k:
                if nums[i] + nums[j] + nums[k] < 0:
                    j += 1
                elif nums[i] + nums[j] + nums[k] > 0:
                    k -= 1
                elif j < k:
                    t = (nums[i], nums[j], nums[k])
                    ans.append(t)
                    j += 1
                    k -= 1
        filter_list = list(set(ans))
        ret = [list(x) for x in filter_list]
        return ret
View Code

 

 2024.07.01

131. Palindrome Partitioning M: 水题

90. Subsets II M:水题

class Solution:
    def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
        ret = set()
        n = len(nums)
        nums.sort()
        for s in range(1<<n):
            t = []
            for i in range(n):
                if (1<<i) & s:
                    t.append(nums[i])
            ret.add(tuple(t))
        return [list(x) for x in list(ret)]
View Code

51. N-Queens M:水题

class Solution:
    def doSolve(self, now: int, n: int, mp: List[str]):

        if now == n:
            self.ret.append(mp.copy())
            return 
        for i in range(n):
            if not self.col[i] and not self.sum[i+now] and not self.diff[i - now + n]:
                self.col[i] = self.sum[i+now] = self.diff[i-now+n] = True
                t = '.' * i + 'Q' + '.' * (n-i-1)
                mp.append(t)
                self.doSolve(now+1, n, mp)
                mp.pop()
                self.col[i] = self.sum[i+now] = self.diff[i-now+n] = False

    def solveNQueens(self, n: int) -> List[List[str]]:
        self.ret = []
        self.col = [False] * n
        self.sum = [False] * (n<<1)
        self.diff = [False] * (n<<1)
        self.doSolve(0, n, [])
        return self.ret
View Code

 

 2024.7.11. sliding window

121. Best Time to Buy and Sell Stock E, T1, S1

3. Longest Substring Without Repeating Characters M, TN, SN

find the length of the longest substring without repeating characters

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        from queue import Queue
        q = Queue()
        vis = {}
        ans = 0
        for x in s:
            
            if not vis.get(x) or vis[x] == 0:
                vis[x] = 1
                q.put(x)
                ans = max(q.qsize(), ans)
                # print(x, ans)
            else:
                cnt = 0
                while True:
                    t = q.get()
                    vis[t] = 0
                    # print(t)
                    if t == x:
                        q.put(x)
                        vis[x] = 1
                        break
                    # cnt += 1
        return ans
View Code

424. Longest Repeating Character Replacement M, TN, SN

string s & t, You can choose any character of the string and change it to any other uppercase English character. You can perform this operation at most times.

Return the length of the longest substring containing the same letter you can get after performing the above operations.

class Solution:
    def characterReplacement(self, s: str, k: int) -> int:
        gr = set()
        for x in s:
            gr.add(x)
        ret = 0
        if k == 0:
            ans = 1
            for i in range(1, len(s)):
                if s[i] == s[i-1]:
                    ans += 1
                else:
                    ret = max(ret, ans)
                    ans = 1
            ret = max(ret, ans)
        else:
            from queue import Queue
            for x in gr:
                cnt = k
                q = Queue()
                for ch in s:
                    if ch != x:
                        if cnt == 0:
                            while q.qsize():
                                t = q.get()
                                if t != x:
                                    break
                        else:
                            cnt -= 1
                    q.put(ch)
                    ret = max(ret, q.qsize())
        return ret    
View Code

567. Permutation in String M, TN, SN

 Given two strings s1 and s2, return true if s2 contains a permutation of s1, or  false otherwise. (permutation->same # of character)
class Solution:
    def checkInclusion(self, s1: str, s2: str) -> bool:
        dic = {}
        for ch in s1:
            dic[ch] = dic.get(ch, 0) + 1
        from queue import Queue
        q = []
        head, tail = 0, 1
        ret = 0
        for ch in s2:
            if ch in dic:
                dic[ch] -= 1
                if dic[c]
                q.put(ch)
                if q.qsize() == len(s1):
                    return True
                # print(ch, q.qsize(), dic)
            else:
                while not q.empty():
                    t = q.get()
                    dic[t] += 1
        return False

        
View Code

76. Minimum Window Substring H, TN, SN

Given two strings s and t of lengths m and n respectively, return the minimum window substring of s such that every character in t (including duplicates) is

included in the window. 加强版567,real hard, 定义无用元素a: 不在t中的,在substring中但重复次数>在t中重复次数, 出队:{a}*{not a}{a}* [{not a}..... queue]

class Solution:
    def minWindow(self, s: str, t: str) -> str:
        dic = {}
        for ch in t:
            dic[ch] = dic.get(ch, 0) + 1
        
        q = []
        head, tail = 0, 0
        ret = 1e9
        ret_s = ""
        cnt = 0
        for ch in s:
            if ch in dic:
                dic[ch] -= 1
                q.append(ch)
                tail += 1
                if dic[ch] >= 0:
                    cnt += 1
                elif dic[ch] < 0:
                    while head < tail:
                        tt = q[head]
                        if tt not in dic:
                            head += 1
                        elif dic[tt] < 0:
                            head += 1
                            dic[tt] += 1
                        else:
                            break
                # print(ch, cnt)
                if cnt == len(t):
                    # print('haha', ch, q[head: tail], ret)
                    if tail - head < ret:
                        ret = tail - head
                        ret_s = ""
                        for i in range(head, tail):
                            ret_s += q[i]
                    fg = 0
                    while head < tail:
                        tt = q[head]
                        if tt not in dic:
                            head += 1
                            continue
                        if dic[tt] >= 0 and fg:
                            break
                        head += 1
                        dic[tt] += 1
                        if dic[tt] >= 1:
                            cnt -= 1
                            fg = 1
            else:
                if tail - head > 0:
                    q.append(ch)
                    tail += 1
            # print(ch, dic, q[head: tail], cnt, ret)
        return ret_s
View Code

239. Sliding Window Maximum H, TN, SN

第一想法,TNlogN, sortedlist(logN取出优先队列);TN:维护一个双向队列,保持递减,队首元素要在窗口内,可以保证这个是当前window Max

class Solution:
    def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
        from sortedcontainers import SortedList
        sl = SortedList()
        ret = []
        for i in range(k):
            sl.add(nums[i])
        ret.append(sl[-1])
        for i in range(k, len(nums)):
            sl.add(nums[i])
            sl.remove(nums[i-k])
            ret.append(sl[-1])
            # print(sl)
        return ret
        

        
sorted list
class Solution:
    def minWindow(self, s: str, t: str) -> str:
        dic = {}
        for ch in t:
            dic[ch] = dic.get(ch, 0) + 1
        
        q = []
        head, tail = 0, 0
        ret = 1e9
        ret_s = ""
        cnt = 0
        for ch in s:
            if ch in dic:
                dic[ch] -= 1
                q.append(ch)
                tail += 1
                if dic[ch] >= 0:
                    cnt += 1
                elif dic[ch] < 0:
                    while head < tail:
                        tt = q[head]
                        if tt not in dic:
                            head += 1
                        elif dic[tt] < 0:
                            head += 1
                            dic[tt] += 1
                        else:
                            break
                # print(ch, cnt)
                if cnt == len(t):
                    # print('haha', ch, q[head: tail], ret)
                    if tail - head < ret:
                        ret = tail - head
                        ret_s = ""
                        for i in range(head, tail):
                            ret_s += q[i]
                    fg = 0
                    while head < tail:
                        tt = q[head]
                        if tt not in dic:
                            head += 1
                            continue
                        if dic[tt] >= 0 and fg:
                            break
                        head += 1
                        dic[tt] += 1
                        if dic[tt] >= 1:
                            cnt -= 1
                            fg = 1
            else:
                if tail - head > 0:
                    q.append(ch)
                    tail += 1
            # print(ch, dic, q[head: tail], cnt, ret)
        return ret_s
Deque

 

 

2024.8.26 & 2024.8.27

143. Reorder List. M, TN, S1, backtrace

class Solution {
public:
    ListNode *hh;

    void reorder(ListNode* lst, ListNode* now){
        if (now->next != nullptr)
            reorder(now, now->next);
        if(hh == nullptr || hh->next == nullptr)
            return;
        if(lst != nullptr)
            lst->next = nullptr;
        // cout<<(now->val)<<" ";
        // cout<<(hh->val)<<"\n";
        
        now->next = hh->next;
        hh->next = now;
        hh = now->next; 
        
        return;   
    }
    void reorderList(ListNode* head) {
        hh = head;
        reorder(nullptr, head);
        for(auto t = head; t->next != nullptr; t = t->next)
            cout<<(t->val)<<"\n";
    }
};
View Code

19. Remove Nth Node From End of List. M, TN, S1, two pointer

138. Copy List with Random Pointer M, TN, SN, hash table

"""
# Definition for a Node.
class Node:
    def __init__(self, x: int, next: 'Node' = None, random: 'Node' = None):
        self.val = int(x)
        self.next = next
        self.random = random
"""

class Solution:
    from collections import defaultdict
    def copyRandomList(self, head: 'Optional[Node]') -> 'Optional[Node]':
        if not head:
            return None
        
        mp = defaultdict()
        current = head
        
        # First pass: Create the mapping from the original nodes to their copies
        while current:
            new_node = Node(current.val)
            mp[current] = new_node
            current = current.next
            
        # Second pass: Set the next and random pointers for the copied nodes
        current = head
        while current:
            mp[current].next = mp.get(current.next)
            mp[current].random = mp.get(current.random)
            current = current.next
        
        return mp[head]
View Code

235. Lowest Common Ancestor of a Binary Search Tree M, TN, S1

class Solution:
    
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        anc = {}
        dep = {}
        
        def dfs(now, prev):
            anc[now] = [-1] * 20
            if prev is not None:
                dep[now] = dep[prev] + 1
                anc[now][0] = prev
            else:
                dep[now] = 0
            
            for u in range(1, 20):
                if anc[now][u-1] in anc:
                    anc[now][u] = anc[anc[now][u-1]][u-1]
                    
            if now.left:
                dfs(now.left, now)
            if now.right:
                dfs(now.right, now)
        
        dfs(root, None)
        
        if dep[p] < dep[q]:
            p, q = q, p
        
        for u in range(19, -1, -1):
            if anc[p][u] != -1 and dep[anc[p][u]] >= dep[q]:
                p = anc[p][u]
                
        if p == q:
            return p
        
        for u in range(19, -1, -1):
            if anc[p][u] != anc[q][u]:
                p = anc[p][u]
                q = anc[q][u]
                
        return anc[p][0]
LCA
class Solution:
    
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        if p.val == root.val or q.val == root.val:
            return root
        if p.val < root.val and q.val < root.val:
            return self.lowestCommonAncestor(root.left, p, q)
        if p.val > root.val and q.val > root.val:
            return self.lowestCommonAncestor(root.right, p, q)
        return root
BST

102. Binary Tree Level Order Traversal199. Binary Tree Right Side View  M, TN, SN, same approach

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    
    def rightSideView(self, root: Optional[TreeNode]) -> List[int]:
        dep = {}
        nodes = {}
        max_dep = 0
        def dfs(now, prev):
            nonlocal dep, nodes, max_dep
            if prev:
                dep[now] = dep[prev] + 1
            else:
                dep[now] = 0
            max_dep = max(max_dep, dep[now])
            if dep[now] in nodes:
                nodes[dep[now]].append(now.val)
            else:
                nodes[dep[now]] = [now.val]
            if now.left:
                dfs(now.left, now)
            if now.right:
                dfs(now.right, now)
        ret = []
        if root:
            dfs(root, None)
            ret = [nodes[d][-1] for d in range(max_dep+1)]
        return ret
View Code

1448. Count Good Nodes in Binary Tree. 水题

146. LRU Cache M,细节比较多

class Node:
    def __init__(self, key = None, val = None, prev = None, nxt = None):
        self.nxt = nxt
        self.prev = prev
        self.val = val
        self.key = key

class LRUCache:

    def __init__(self, capacity: int):
        self.head = Node()
        self.head.val = -1
        self.tail = None
        self.table = {}
        self.size = 0
        self.cap = capacity

    def get(self, key: int) -> int:
        if key not in self.table:
            return -1
        val = self.table[key].val
        self.put(key, val)
        return val
        

    def put(self, key: int, value: int) -> None:
        if key in self.table:
            old_node = self.table[key]
            old_node.val = value
            # print(old_node)
            old_node.prev.nxt = old_node.nxt
            if old_node.nxt:
                old_node.nxt.prev = old_node.prev
            elif old_node.prev != self.head:
                self.tail = old_node.prev
            else:
                self.tail = old_node
            old_node.nxt = self.head.nxt
            old_node.prev = self.head
            self.head.nxt = old_node
            if old_node.nxt:
                old_node.nxt.prev = old_node
        else:
            if self.size == self.cap:
                # print(self.size, self.cap, self.table, self.tail.key)
                del self.table[self.tail.key]
                self.tail.prev.nxt = None
                self.size -= 1
                if self.tail.prev != self.head:
                    self.tail = self.tail.prev
            new_node = Node(key, value, self.head, self.head.nxt)
            self.head.nxt = new_node
            self.size += 1
            self.table[key] = new_node
            if self.tail == None or new_node.nxt == None:
                self.tail = new_node
            elif new_node.nxt:
                new_node.nxt.prev = new_node
            
        


# Your LRUCache object will be instantiated and called as such:
# obj = LRUCache(capacity)
# param_1 = obj.get(key)
# obj.put(key,value)
View Code

23. Merge k Sorted Lists H, 优先队列,但实际上可以少开extra space,不过同一个数量级

/**
 * 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* mergeKLists(vector<ListNode*>& lists) {
        priority_queue<int, vector<int>, greater<int> > q;
        for(int i = 0; i < lists.size(); i++){
            ListNode *head = lists[i];
            while(head != nullptr) {
                q.push(head->val);
                head = head->next;
            }
        }
        ListNode *ret, *now;
        ret = new ListNode();
        now = ret;
        while(!q.empty()){
            int val = q.top();
            q.pop();
            ListNode *node = new ListNode(val);
            now->next = node;
            now = now->next;
        }
        return ret->next;

    }
};
View Code

25. Reverse Nodes in k-Group H,dfs

/**
 * 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 *newhead, *oldhead;
    pair<ListNode*, ListNode*> reversePart(int dep, int k, ListNode* now, ListNode* pre){
        if(dep == k) {
            ListNode *tmp = now->next;
            now->next = pre;
            pair<ListNode*, ListNode*> ret(now, tmp);
            return ret;
        }
        cout<<k<<" "<<now->val<<endl;
        pair<ListNode*, ListNode*> ret = reversePart(dep + 1, k, now->next, now);
        now->next = pre;
        return ret;
    }
    ListNode* reverseKGroup(ListNode* head, int k) {
        ListNode *now = head, *oldnow = nullptr;
        int sz = 0, cnt = 0;
        while(now != nullptr){now = now->next;sz++;}
        if(sz < k) return head;
        int t = sz / k;
        pair<ListNode*, ListNode*> ret;
        now = head;
        while(cnt < t){
            cnt++;
            ret = reversePart(1, k, now, nullptr);
            if(oldnow != nullptr) oldnow->next = ret.first;
            oldnow = now;
            now = ret.second;
            if(cnt == 1) head = ret.first;
            
        }
        if(sz % k) oldnow->next = ret.second;
        return head;
    }
};
View Code

 


 

 

 

 

 

posted @ 2023-11-08 23:16  Ed_Sheeran  阅读(129)  评论(0编辑  收藏  举报