GitHub链接:https://github.com/WilliamWuLH/LeetCode
如果你觉得不错可以 ⭐Star 和 Fork ❤
31.Next Permutation
找规律:
找到下一个按照字典序的排列,所以思路应该是从排列的尾部开始找。
首先从排列的尾部往前找,找到第一个 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;
}
};
32.Longest Valid Parentheses
动态规划:
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;
}
};
用stack栈 存 “(” 的位置:
在栈中的栈底元素是此时有效括号字符串的开始位置。
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;
}
};
33.Search in Rotated Sorted Array
二分查找:
由于该“旋转有序数组”的特性,在对其进行划分时,划分出来的两个部分一定有一部分是完全有序的,另一部分是部分有序的。
根据这个特性,我们可以取出两个部分中完全有序的那一部分进行讨论:
由于数组是完全有序的,所以可以通过判断大小知道目标数字是否在这一部分。
如果目标数字不在完全有序的那一部分,那么一定在另一部分。
通过上述的判断可以进行二分查找,不断缩小查找范围,直到找到目标数字的位置或者没找到目标数字。
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;
}
};
34.Find First and Last Position of Element in Sorted Array
二分法 + 边界判断 + 取值判断:
二分法的重点和难点主要为:
- 左右边界的取值,主要是右边界( size 还是 size - 1 )。
- while 循环的判断条件( < 还是 <= ),这和左右边界的取值有关。
- 中间位置的计算,使用 left + (right - left)/2 可以避免溢出。
- 不要用 else,全部都用 else if 把情况说明清楚。
- 针对不同情况,左右边界应该如何收缩:这和一开始左右边界的取值有关
- 最后取值(取出位置或者是坐标)时,需要判断该位置是否有效(即该位置在合法范围内),并且需要判断该位置的值是否为目标数值。
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;
}
};
35.Search Insert Position
二分查找:
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;
}
};