20230629-Codetop

57 阅读1分钟

leetcode-300 最长递增子序列

动态规划复健典型题。说实话子序列的题我都比较头疼。这题的状态转移不难,但是不好想,需要在每一个i往前遍历。定义dp[i]为到i位置为止最长的递增子序列。如果nums[j] < nums[i],则dp[i] = max(dp[i], dp[j] + 1)。解释:从每个i位置往前遍历,如果遇到nums[j]比nums[i]小的,两种选择——以dp[j]所代表的最长递增子序列为前置,加上nums[i],作为新的最长递增子序列,或者不选择dp[j]所代表的最长递增子序列。去上述两种选择的最大值。从前向后遍历,base case为首项最短是1。


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

leetcode-33 搜索旋转排序数组

这题要求O(logn)明显就是二分,但是麻烦的点也是本题的核心是数组并非完全有序,而是分段有序。且题意决定了左有序区间的最小值必然大于右有序区间的最大值。二分查找时需要首先判断当前mid处于什么区间内,

class Solution {
public:
    int search(vector<int>& nums, int target) {
        // 题意决定了两段有序区间必然是左区间完全大于右区间
        int n = nums.size();
        if(n == 1) return nums[0] == target ? 0 : -1;
        int l = 0, r = n - 1;
        while(l <= r){
            int mid = (l + r) >> 1;
            if(nums[mid] == target) return mid;
            if(nums[0] <= nums[mid]){ //需要先判断属于哪个有序区间
                if(nums[0] <= target && target < nums[mid]){ // 处于左有序区间
                    r = mid - 1;
                }
                else l = mid + 1; // 处于中间不连续区间
            }
            else{
                if(nums[mid] < target && target <= nums[n - 1]){ // 处于右有序区间
                    l = mid + 1;
                }
                else r = mid - 1; // 处于中间不连续区间
            }
        }
        return -1;
    }
};