LeetCode 31-40题

本博客记录的是 LeetCode 31 到 40 题的题解

之前很少使用的语法

reverse(nums.begin() + k, nums.end());
stk.top();
stk.size();
stk.pop();

t += to_string(k - j) + s[j];   // 注意 += 原地操作
nums.reverse()
nums.append(12)
x = nums.pop()  #会返回数值
nums[-1]

31. Next Permutation

C++ code

class Solution {
public:
    // 有点类似于找规律的题目,直接多写几个就可以找到规律了
    void nextPermutation(vector<int>& nums) {
        int n = nums.size(), l = nums.size() - 1, r = nums.size() - 1;
        for (int i = n - 2; i >= 0; i -- ) {
            if (nums[i] < nums[i + 1]) {
                break;
            }
            l -= 1;
        }
        int i = l, j = r;
        while (i < j) {
            swap(nums[i], nums[j]);
            i ++, j --;
        }
        if (l == 0) {
            return;
        } else {
            for (int i = l; i <= r; i ++ ) {
                if (nums[i] > nums[l - 1]) {
                    swap(nums[i], nums[l - 1]);
                    break;
                }
            }
        }
        
    }
};

STL写法

class Solution {
public:
    // 有点类似于找规律的题目,直接多写几个就可以找到规律了
    void nextPermutation(vector<int>& nums) {
        int n = nums.size();
        int k = n - 1;
        while (k > 0 && nums[k - 1] >= nums[k]) k --;
        if (k <= 0) {
            reverse(nums.begin(), nums.end());
        } else {
            int t = k;
            while (t + 1 < n && nums[k - 1] < nums[t + 1])   t += 1;
            swap(nums[k - 1], nums[t]);
            reverse(nums.begin() + k, nums.end());
        }
        
    }
};

python code

class Solution:
    def nextPermutation(self, nums: List[int]) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        n = len(nums)
        l, r = n - 1, n - 1
        for i in range(n - 2, -1, -1):
            if nums[i] >= nums[i + 1]:  # 这里需要有个等号
                l -= 1
            else:
                break
        i, j = l, r
        while i < j:
            nums[i], nums[j] = nums[j], nums[i]
            i, j = i + 1, j - 1
        if l == 0:
            return
        else:
            print(nums)
            for i in range(l, n):
                if nums[i] > nums[l - 1]:
                    nums[i], nums[l - 1] = nums[l - 1], nums[i]
                    break
            print(nums)
            return

32. Longest Valid Parentheses

这个题目就是恶心在思路上,即使你能想到需要使用栈来解决到匹配问题,也很难想到上一个未匹配的括号位置,就是他丫的最大的匹配边界。
所以说,我们使用栈来记录他的'('位置,然后查看他所匹配的pop后的top位置,可以得知')'的最大匹配,然后更新res

c++代码

class Solution {
public:
    int longestValidParentheses(string s) {
        int res = 0, n = s.size();
        stack<int> stk;
        for (int i = 0, start = -1; i < n; i ++ ) {
            if (s[i] == '(')    stk.push(i);
            else {
                if (stk.size()) {
                    stk.pop();
                    if (stk.size()) {
                        res = max(res, i - stk.top());
                    } else {
                        res = max(res, i - start);
                    }
                } else {
                    start = i;
                }
            }
        }
        return res;
    }
};

python 代码

class Solution:
    def longestValidParentheses(self, s: str) -> int:
        n, start, res = len(s), -1, 0
        stk = []
        for i in range(n):
            if s[i] == '(':
                stk.append(i)
            else:
                if not stk:
                    start = i
                else:
                    stk.pop()
                    if not stk:
                        res = max(res, i - start)
                    else:
                        res = max(res, i - stk[-1])
        return res

33. Search in Rotated Sorted Array

两次二分,第一次是找旋转点,第二次是在有序数组中找target

c++代码

class Solution {
public:
    int get_idx(vector<int>& nums, int l, int r, int target) {
        int mid;
        if (target > nums[r] || target < nums[l]){
            return -1;
        } else {
            while (l < r) {
                mid = l + r + 1 >> 1;
                if (nums[mid] <= target) {
                    l = mid;
                } else {
                    r = mid - 1;
                }
            }
            if (nums[l] == target) {
                return l;
            } else {
                return -1;
            }
        }
        
    }


    int search(vector<int>& nums, int target) {
        // 首先,二分找分界点
        int n = nums.size();
        if (nums[0] <= nums[n - 1]) {    // 没有旋转
            return get_idx(nums, 0, n - 1, target);
        } else {    // 旋转了,需要二分找分界点 mid 
            int l = 0, r = n - 1, mid, x = nums[0];
            while (l < r) {
                mid = l + r >> 1;
                if (nums[mid] < x) {
                    r = mid;
                } else {
                    l = mid + 1;
                }
            }
            printf("split mid=%d\n", l);
            if (target > nums[n - 1]) {
                return get_idx(nums, 0, l - 1, target);
            } else {
                return get_idx(nums, l, n - 1, target);
            }
        }
    }
};

python 代码

class Solution:
    def get_idx(self, nums, l, r, target):
        if nums[l] > target or nums[r] < target:
            return -1
        while l < r:
            mid = (l + r + 1) // 2
            if nums[mid] <= target:
                l = mid
            else:
                r = mid - 1
        return l if nums[l] == target else -1

    def search(self, nums: List[int], target: int) -> int:
        n = len(nums)
        if nums[0] <= nums[n - 1]:  # no rotation
            return self.get_idx(nums, 0, n - 1, target)
        else:
            l, r = 0, n - 1
            while l < r:
                mid = (l + r) // 2
                if nums[mid] < nums[0]:
                    r = mid
                else:
                    l = mid + 1
            if nums[n - 1] >= target:
                return self.get_idx(nums, l, n - 1, target)
            else:
                return self.get_idx(nums, 0, l - 1, target)

34. Find First and Last Position of Element in Sorted Array

二分查找的基础题目

c++ 代码

class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        vector<int> res;
        if (nums.size() <= 0) {
            return vector<int>{-1, -1};
        }
        int x = target;
        int l, r, mid, n = nums.size();
        l = 0, r = n - 1;
        // 大于等于 x 的最小值
        while (l < r) {
            mid = l + r >> 1;
            if (nums[mid] >= x) {
                r = mid;
            } else {
                l = mid + 1;
            }
        }
        int res1, res2;
        if (nums[l] != target) {
            return vector<int> {-1, -1};
        }
        res.push_back(l);
        // 小于等于 x 的最大值
        l = 0, r = n - 1;
        while (l < r) {
            mid = l + r + 1 >> 1;
            if (nums[mid] <= x) {
                l = mid;
            } else {
                r = mid - 1;
            }
        }
        res.push_back(l);
        return res;
    }
};

python 代码

class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        n = len(nums)
        if n == 0 or target > nums[-1] or target < nums[0]:
            return [-1, -1]
        
        # higher target min value
        l, r = 0, n - 1
        while l < r:
            mid = (l + r) // 2
            if nums[mid] >= target:
                r = mid
            else:
                l = mid + 1
        if nums[l] != target:
            return [-1, -1]
        res = [l]

        # lower target max value
        l, r = 0, n - 1
        while l < r:
            mid = (l + r + 1) // 2
            if nums[mid] <= target:
                l = mid
            else:
                r = mid - 1
        res.append(l)
        
        return res

35. Search Insert Position

就是寻找大于等于 target 的最小值所在的位置,相当于 34 题一半的代码量

class Solution:
    def searchInsert(self, nums: List[int], target: int) -> int:
        # 寻找大于等于 target 的最小值所在的位置
        n = len(nums)
        if nums[-1] < target:
            return n
        l, r = 0, n - 1
        while l < r:
            mid = (l + r) // 2
            if nums[mid] >= target:
                r = mid
            else:
                l = mid + 1
        return l

36. Valid Sudoku

按照数独给出的3条规则进行暴力模拟即可
python 代码

class Solution:
    def isValidSudoku(self, board: List[List[str]]) -> bool:
        visited = [False] * 12
        for i in range(9):
            for k in range(10):
                visited[k] = False
            for j in range(9):
                if board[i][j] == '.':
                    continue
                elif visited[int(board[i][j])] == True:
                    return False
                else:
                    visited[int(board[i][j])] = True
            for k in range(10):
                visited[k] = False
            for j in range(9):
                if board[j][i] == '.':
                    continue
                elif visited[int(board[j][i])] == True:
                    return False
                else:
                    visited[int(board[j][i])] = True
        for i in range(0, 7, 3):
            for j in range(0, 7, 3):
                for k in range(10):
                    visited[k] = False
                for u in range(3):
                    for v in range(3):
                        if board[i+u][j+v] == '.':
                            continue
                        elif visited[int(board[i+u][j+v])] == True:
                            return False
                        else:
                            visited[int(board[i+u][j+v])] = True
        return True

37. Sudoku Solver

暴力 DFS即可,不过需要提前打好表(行列以及小3X3矩阵)进行加速

class Solution:
    def solveSudoku(self, a: List[List[str]]) -> None:
        """
        Do not return anything, modify board in-place instead.
        """
        rows = [[False] * 10 for i in range(10)]
        cols = [[False] * 10 for i in range(10)]
        place = [[[False] * 10 for i in range(4)] for j in range(4)]
        for i in range(9):
            for j in range(9):
                if a[i][j] == '.':
                    continue
                else:
                    rows[i][int(a[i][j])] = True
                    cols[j][int(a[i][j])] = True
                    place[i//3][j//3][int(a[i][j])] = True
        self.dfs(0, 0, a, rows, cols, place)
    
    def dfs(self, i, j, a, rows, cols, place):
        if i >= 9:
            return True
        if a[i][j] != '.':
            if j == 8:
                return self.dfs(i + 1, 0, a, rows, cols, place)
            else:
                return self.dfs(i, j + 1, a, rows, cols, place)
        for u in range(1, 10):
            if rows[i][u] == False and cols[j][u] == False and place[i//3][j//3][u] == False:
                rows[i][u] = cols[j][u] = place[i//3][j//3][u] = True
                a[i][j] = str(u)
                if j == 8:
                    if self.dfs(i + 1, 0, a, rows, cols, place):
                        return True
                elif self.dfs(i, j + 1, a, rows, cols, place):
                    return True
                rows[i][u] = cols[j][u] = place[i//3][j//3][u] = False
                a[i][j] = '.'
        return False

38. Count and Say

就是查找数字,进行模拟

class Solution {
public:
    string countAndSay(int n) {
        string s = "1";
        for (int i = 2; i <= n; i ++ ) {
            string t = "";
            for (int j = 0; j < s.size();) {
                int k = j + 1;
                while (k < s.size() && s[k] == s[j])    k ++;
                t += to_string(k - j) + s[j];   // 注意 += 原地操作
                j = k;
            }
            s = t;
        }
        return s;
    }
};
class Solution:
    def countAndSay(self, n: int) -> str:
        x = '1'
        for i in range(1, n):
            x += ' '
            y = ''
            cnt = 1
            for j in range(1, len(x)):
                if x[j] == x[j - 1]:
                    cnt += 1
                else:
                    y += str(cnt) + x[j - 1]
                    cnt = 1
            x = y
            # print(f"cnt={i+1}, x={x}")
        return x

39. Combination Sum

完全背包板子题

class Solution:
    def combinationSum(self, t: List[int], m: int) -> List[List[int]]:
        f = [[False] * 510 for i in range(40)]
        f[0][0] = True
        n = len(t)
        a = [0]
        a.extend(t)
        print(a)
        for i in range(1, n + 1):
            for j in range(0, m + 1):
                if j < a[i]:
                    f[i][j] = f[i - 1][j]
                else:
                    f[i][j] = (f[i - 1][j] or f[i][j - a[i]])
        if f[n][m] == False:
            return []
        res = []
        tmp = []
        self.dfs(n, m, a, f, tmp, res)
        return res

    def dfs(self, i, j, a, f, tmp, res):
        if j == 0:
            print(tmp)
            res.append(tmp[:])  # 注意,这里需要是[:],不然dfs会修改他的共享内存
            return
        if j >= a[i] and f[i][j - a[i]] == True:
            tmp.append(a[i])
            self.dfs(i, j - a[i], a, f, tmp, res)
            tmp.pop()
        if i >= 1 and f[i - 1][j] == True:
            self.dfs(i - 1, j, a, f, tmp, res)

40. Combination Sum II

感觉这个题目出的比较恶心,算法不难,但是出题人有意把你往01背包上绕,但是01背包很难解决方案输出不重复的这个问题,因为它将每一个物品都作为独一无二的,即使他们的 数值一样
所以说,这个题目还是作为多重背包比较好,将 candidate 数组处理成为 unique独一无二的数字配上他出现的次数 cnt 进行多重背包。
但是这个多重背包无法使用 二进制优化,否则还是会出现类似于01背包的问题,解决方案不重复这个问题仍会出现,并很难在时限内解决。
当然也可以直接暴搜

// c++暴搜
class Solution {
public:
    vector<vector<int> > ans;
    vector<int> path;
    vector<vector<int>> combinationSum2(vector<int>& cs, int target) {
        sort(cs.begin(), cs.end());
        dfs(0, cs, target);
        return ans;
    }

    void dfs(int i, vector<int> &cs, int target) {
        if (target == 0) {
            ans.push_back(path);
            return;
        }
        if (i == cs.size()) {
            return;
        }
        int j = i + 1;
        while (j < cs.size() && cs[i] == cs[j]) j ++;
        int cnt = j - i;

        for (int k = 0; k <= cnt && target >= k * cs[i]; k ++ ) {
            if (k)  // 注意这个 if k
                path.push_back(cs[i]);
            dfs(j, cs, target - k * cs[i]);
        }
        for (int k = 1; k <= cnt && target >= k * cs[i]; k ++ )
            path.pop_back();
    }
};
# python 多重背包
class Solution:
    def combinationSum2(self, a: List[int], m: int) -> List[List[int]]:
        # 预处理成多重背包
        s = [0] * len(a)
        a.sort()
        j, s[0], n = 1, 1, len(a)
        for i in range(1, n):
            if a[i] == a[i - 1]:
                s[j - 1] += 1
            else:
                a[j] = a[i]
                s[j] = 1
                j += 1
        for i in range(j, n):
            s.pop()
            a.pop()

        # dp
        f = [[False] * 40 for i in range(110)]
        f[0][0] = True
        n = len(a)
        for i in range(1, n + 1):
            for j in range(m + 1):
                k, f[i][j] = 1, f[i - 1][j]
                while f[i][j] == False and j >= k * a[i - 1] and k <= s[i - 1]:
                    f[i][j] = f[i - 1][j - k * a[i - 1]]
                    k += 1
        if not f[n][m]:
            return []
        
        res, tmp = [], []
        self.dfs(n, m, a, s, f, res, tmp)
        return res
    
    def dfs(self, i, j, a, s, f, res, tmp):
        if j == 0:  # recursion ending
            res.append(tmp[:])
            return
        for k in range(0, s[i - 1] + 1):    # count
            if j >= k * a[i - 1]:
                if f[i - 1][j - k * a[i - 1]]: # True
                    tmp.extend([a[i - 1]] * k)
                    self.dfs(i - 1, j - k * a[i - 1], a, s, f, res, tmp)
                    for u in range(k):
                        tmp.pop()
            else:
                break
        return

posted @ 2022-01-04 18:46  lucky_light  阅读(55)  评论(0编辑  收藏  举报