31. Next Permutation
题目描述: 找到全排列中按升序的下一个排列,如123—132,213----231.如果已经是最大值排列,那么返回最小值排列。
解题思路: 思路比较简单,就是从后往前,找到第一个不符合排列规律的数,然后再在它后面找一个最小的大于他的数,交换位置,最后把后面的数排序从而取得最小值排列。可以确定的是,从后往前,也就是从右往左,如果是按升序排列的,那么就是规则的,也就是找到第一个左边数小于右边数的位置就行。错了很多次,是因为边界条件没有理清楚,后面突然顿悟。C++还有一个库函数,一条代码解决。。。。
AC代码:
# python
class Solution(object):
def nextPermutation(self, nums):
"""
:type nums: List[int]
:rtype: None Do not return anything, modify nums in-place instead.
"""
tmp = len(nums)-2
while tmp >= 0 and nums[tmp] >= nums[tmp+1]: tmp -= 1 # 找到第一个不符合条件的位置
if tmp >= 0:
i = 1
while tmp >= 0 and nums[-i] <= nums[tmp]: i += 1 # 找到这个位置后面最小的大于该位置数的数
nums[tmp],nums[-i] = nums[-i],nums[tmp] # 交换位置
nums[tmp+1:] = sorted(nums[tmp+1:]) # 排序
else:
nums.sort() # 最小值序列
32. Longest Valid Parentheses
题目描述: 给一个全由左右 括号组成的字符串,找出最长的括号配对正确的子串长度。如“)(()()))”,返回6
解题思路: 乍一看题目,标成hard难度,读了一下题就跳过了,后来想想这道题似乎也不是很难。看到括号匹配,那么不出意外就是用栈来解决,但是传统的栈并不奏效,因此要改良一下,首先栈里记录的信息,除了记录左括号以外,还可能记录右括号,另外,还要附加一条重要的信息,就是当前字符的位置,这样才能结算答案。然后碰到左括号,进栈,这没问题,碰到右括号就要分情况讨论了,
1)如果此时栈顶存的是左括号,那么可以弹出,并且结算距离。
2)如果此时栈顶存的是右括号,那么不匹配,直接把当前的右括号一并进栈。
3)如果此时栈为空,那么也属于不匹配,仍然压栈。
接下来的一步很关键,就是结算距离,也就是结算答案,每次从栈中弹出元素,就说明匹配是成功的,这时候的距离,应该是当前右括号,到栈顶的左括号的下一个元素的位置,这点很关键,因为如果直接结算这左右括号的距离就会产生一种误判,如"()()()"这样的串,答案最终会结算成2。所以应该结算的是当前位置到栈中倒数第二个位置的元素的距离。
那么这样又出现了一个新的问题,如果栈为空,就无法找到栈中的第二个元素,也就会产生前文所诉的误判,那么为了解决这个问题,可以在初始化栈的时候,就先压入一个右括号,并且把他的下标设为-1,以保证每次从栈中弹出元素时,栈里都至少存在两个元素,这样不仅解决了这个问题,也简化了代码的判断逻辑,从三种情况,简化到了两种情况。
AC代码:
class Solution(object):
def longestValidParentheses(self,s):
res = [(-1,')')] # 初始先放入一个右括号,保证栈不为空
ans = 0
for j,i in enumerate(s):
if i == '(': # 碰到左括号,压栈
res.append((j,'('))
elif i == ')' and res[-1][1] == '(': # 碰到右括号,如果栈顶存在左括号,那么弹出,并结算距离
ans = max(ans,j-res[-2][0])
res.pop()
else: # 如果栈顶不是左括号,那么将此时的右括号也压入栈中。
res.append((j,')'))
return ans
33. Search in Rotated Sorted Array
题目描述: 在发生位移的升序数组里找一个数,要求时间复杂度O(logN)以内。如在4567123找2。
解题思路: 一看题就可以知道是一个典型的二分,只不过需要多加几条判断去控制左右区间的选择。再理解一下题目可以发现,这样的序列是有一个性质的,那就是,要么左半边是升序的序列,要么右半边是升序的序列。要么都是升序的序列。总以会有一边是升序的,那就可以利用这点来解题。
AC代码:
// C++
class Solution {
public:
int search(vector<int>& nums, int target) {
int left = 0,right = nums.size()-1,mid;
while(left <= right)
{
mid = (left+right)/2;
if (nums[mid] == target) return mid; // 前面这些都是标准的二分步骤
else if (nums[left] <= nums[mid] && (target >= nums[left] && target <= nums[mid]))
right = mid-1; // 如果左边是升序的,并且目标值属于这个区间,那么去左区间二分。
else if (nums[mid] <= nums[right] && (target >= nums[mid] && target <= nums[right]))
left = mid+1; // 如果右边是升序的,并且目标值属于这个区间,那么去右区间二分。
else if (nums[left] <= nums[mid])
left = mid+1; // 如果左边是升序的,而目标值不属于这个区间,那么去右区间二分。
else
right = mid-1; // 反之,去左半边二分
}
return -1; // 找不到目标值返回-1
}
};
34. Find First and Last Position of Element in Sorted Array
题目描述: 在有序序列目标值可能有重复,找出这个重复区间。
解题思路: C++标准库,lower_bound(),upper_bound(),基于二分查找,既然有库就不愿自己写二分了。
AC代码:
// C++
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
vector<int> res;
int str = lower_bound(nums.begin(),nums.end(),target) - nums.begin();
int end = upper_bound(nums.begin(),nums.end(),target) - nums.begin()-1;
if(str <= end)
{res.push_back(str);res.push_back(end);}
else
{res.push_back(-1);res.push_back(-1);}
return res;
}
};
35. Search Insert Position
题目描述: 有序数组找插入位置。
解题思路: 水题+1.
AC代码:
// C++
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int l = 0 , r = nums.size()-1,mid;
while(l <= r)
{
mid = (l+r)/2;
if (nums[mid] == target) return mid;
else if (nums[mid] < target) l = mid+1;
else r = mid-1;
}
return l;
}
};
36. Valid Sudoku
题目描述: 判断一个数独是否有效,也就是满足三个条件。
1、每行1-9不重复
2、每列1-9不重复
3、9格小方块里的数1-9无重复
解题思路: 简单题,python处理起来比较方便,一个循环搞定。当时还在琢磨,怎么没有个填数独的题,结果下一题就是,不过目前还没解出来。
AC代码:
# python
class Solution(object):
def isValidSudoku(self,board):
for i in range(9):
if 10-board[i].count('.') != len(set(board[i])): # 判断行是否有效,利用set集合元素不重复的性质
return False
tmp = [board[j][i] for j in range(9)]
if 10-tmp.count('.') != len(set(tmp)): # 同上,判断列是否有效
return False
tmp = [board[int(i/3)*3+j][int(i%3)*3+k] for j in range(3) for k in range(3)]
if 10-tmp.count('.') != len(set(tmp)): # 判断小方格是否有效
return False
return True
No. xx
题目描述: 模板
解题思路: 模板
AC代码:
###