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;
}
};