赞
踩
找到下一个按照字典序的排列,所以思路应该是从排列的尾部开始找。
首先从排列的尾部往前找,找到第一个 nums[ i-1 ] < nums[ i ] 的位置,此时说明通过将 nums[ i-1 ] 和排列在 nums[ i-1 ] 后面的并且比 nums[ i-1 ] 大的数 nums[ j ] 互换位置,将得到更大的排列。
如果找不到 nums[ i-1 ] < nums[ i ] 的位置,则说明此时的排列是最大的,直接将整个排列进行反转,得到最小的排列。
若找到 nums[ i-1 ] < nums[ i ] 的位置,此时的任务是找到一个数和 nums[ i-1 ] 进行交换,这个数需要满足:这个数排列在 nums[ i-1 ] 的后面,并且是比 nums[ i-1 ] 大的数中最小的那一个数。
完成交换后,由于 nums[ i-1 ] 已经比之前更大了,所以需要将排在 nums[ i-1 ] 后面的数变为最小的排列,即把在 nums[ i-1 ] 后面的排列进行反转。
完成交换和反转之后便得到了下一个按照字典序的排列。
class Solution { public: void nextPermutation(vector<int>& nums) { int pos = nums.size()-1; while(pos > 0 && nums[pos] <= nums[pos-1]) pos--; reverse(nums.begin()+pos,nums.end()); if(pos > 0){ for(int i=pos;i<nums.size();i++){ if(nums[i] > nums[pos-1]){ swap(nums[pos-1],nums[i]); break; } } } return; } };
class Solution { public: int longestValidParentheses(string s) { int ans = 0; int len = s.length(); vector<int> dp(len, 0); for(int i=1; i<len; i++){ if(s[i] == ')'){ if(s[i-1] == '('){ dp[i] = i-1>0 ? dp[i-2]+2 : 2; } else if( i-1-dp[i-1] >=0 && s[i-1-dp[i-1]] == '('){ if( i-dp[i-1]-2 >= 0){ dp[i] = dp[i-1] + 2 + dp[i-dp[i-1]-2]; } else{ dp[i] = dp[i-1] + 2; } } } ans = max(ans, dp[i]); } return ans; } };
在栈中的栈底元素是此时有效括号字符串的开始位置。
class Solution { public: int longestValidParentheses(string s) { int ans = 0; int len = s.length(); stack<int> front; front.push(-1); for(int i=0; i<len; i++){ if(s[i] == '(') front.push(i); else{ front.pop(); if(front.empty()) front.push(i); else ans = max(ans, i-front.top()); } } return ans; } };
由于该“旋转有序数组”的特性,在对其进行划分时,划分出来的两个部分一定有一部分是完全有序的,另一部分是部分有序的。
根据这个特性,我们可以取出两个部分中完全有序的那一部分进行讨论:
由于数组是完全有序的,所以可以通过判断大小知道目标数字是否在这一部分。
如果目标数字不在完全有序的那一部分,那么一定在另一部分。
通过上述的判断可以进行二分查找,不断缩小查找范围,直到找到目标数字的位置或者没找到目标数字。
class Solution { public: int search(vector<int>& nums, int target) { int left = 0,right = nums.size()-1; while(left <= right){ if(left == right){ if(nums[left] == target) return left; else return -1; } int mid = (left + right)/2; if(nums[mid] == target) return mid; if(nums[left] <= nums[mid]){ if(nums[left] <= target && target < nums[mid]){ right = mid; continue; } else{ left = mid+1; continue; } } else{ if(nums[mid] < target && target <= nums[right]){ left = mid+1; continue; } else{ right = mid; continue; } } } return -1; } };
二分法的重点和难点主要为:
class Solution { public: vector<int> searchRange(vector<int>& nums, int target) { int left = 0,right = nums.size(); vector<int> ans = {-1,-1}; while(left < right){ int mid = left + (right - left)/2; if(nums[mid] == target) right = mid; else if(nums[mid] < target) left = mid+1; else if(nums[mid] > target) right = mid; } if(left < nums.size() && nums[left] == target) ans[0] = left; left = 0,right = nums.size(); while(left < right){ int mid = left + (right - left)/2; if(nums[mid] == target) left = mid+1; else if(nums[mid] < target) left = mid+1; else if(nums[mid] > target) right = mid; } if(right-1 < nums.size() && nums[right-1] == target) ans[1] = right-1; return ans; } };
class Solution { public: int searchInsert(vector<int>& nums, int target) { int left = 0,right = nums.size()-1; while(left <= right){ int mid = left + (right - left)/2; if(nums[mid] == target) return mid; else if(nums[mid] < target) left = mid+1; else if(nums[mid] > target) right = mid-1; } return left; } };
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。