HOT100--Day23--153. 寻找旋转排序数组中的最小值,4. 寻找两个正序数组的中位数,20. 有效的括号
每日刷题系列。今天的题目是《力扣HOT100》题单。
题目类型:二分查找,栈。
关键:
今天的题目都是"多次二分"
153题,掌握"旋转排序数组"的特性和操作。
20题,可以用stack,可以用字符数组原地模拟栈,可以用switch case
153. 寻找旋转排序数组中的最小值
思路:
和最后一个元素比较。
二分查找[0,n-2]的内容,n-1不用管,是比较的对象。
如果x比最后一个数小,要么是最小值,要么x在最小值右侧。right = mid - 1;
如果x大于等于最后一个数。一定有两段,且目前x在第一段。left = mid + 1;
java
class Solution {
public int findMin(int[] nums) {
int n = nums.length;
int left = 0;
int right = n - 2;
// 二分查找[0,n-2]的内容,n-1不用管,是比较的对象
while (left <= right) {
int mid = left + ((right - left) >> 1);
int x = nums[mid];
// 如果x比最后一个数小,要么是最小值,要么x在最小值右侧
if (x < nums[n - 1]) {
right = mid - 1;
} else {
// 如果x大于等于最后一个数。一定有两段,且目前x在第一段。
left = mid + 1;
}
}
return nums[right + 1];
}
}
- 情况一:最小值在最左边,整个数组递增。会一直执行right = mid -1;left一直等于0。最后在right = -1的时候退出循环,这时候返回nums[right+1],就是nums[0],正确。
- 情况二:最小值在最右边,其实也是分成了两端了。会一直执行left = mid +1;right一直等于n-2直到退出循环。这时候返回nums[right+1],就是nums[n-1],正确。
- 其他情况:分成两段,全局最小值,在右段的第一个。最终会因为left>right退出循环,而退出循环时,right会在第一段的最后一个元素,也就是全局最大值的地方,返回nums[right+1],就是第二段的第一个元素,全局最小值。(这里也是退出循环时,left的位置)
4. 寻找两个正序数组的中位数
思路:
先不做,跳过,二刷再做。
java
class Solution {
public double findMedianSortedArrays(int[] a, int[] b) {
if (a.length > b.length) {
// 交换 a 和 b
int[] tmp = a;
a = b;
b = tmp;
}
int m = a.length;
int n = b.length;
// 循环不变量:a[left] <= b[j+1]
// 循环不变量:a[right] > b[j+1]
int left = -1;
int right = m;
while (left + 1 < right) { // 开区间 (left, right) 不为空
int i = (left + right) / 2;
int j = (m + n + 1) / 2 - i - 2;
if (a[i] <= b[j + 1]) {
left = i; // 缩小二分区间为 (i, right)
} else {
right = i; // 缩小二分区间为 (left, i)
}
}
// 此时 left 等于 right-1
// a[left] <= b[j+1] 且 a[right] > b[j'+1] = b[j],所以答案是 i=left
int i = left;
int j = (m + n + 1) / 2 - i - 2;
int ai = i >= 0 ? a[i] : Integer.MIN_VALUE;
int bj = j >= 0 ? b[j] : Integer.MIN_VALUE;
int ai1 = i + 1 < m ? a[i + 1] : Integer.MAX_VALUE;
int bj1 = j + 1 < n ? b[j + 1] : Integer.MAX_VALUE;
int max1 = Math.max(ai, bj);
int min2 = Math.min(ai1, bj1);
return (m + n) % 2 > 0 ? max1 : (max1 + min2) / 2.0;
}
}
20. 有效的括号
思路:
把字符数组模拟成栈,空间复杂度O(1)。
注意,Java字符串转成字符数组时,会复制,所以空间复杂度是O(n)。可以用指针的语言的空间复杂度是O(1)
- 如果是左括号?进栈
- 如果是右括号?
- 首先栈内要有元素,检查跟栈顶元素是否匹配
- 匹配,出栈
- 不匹配,返回false
- 首先栈内要有元素,检查跟栈顶元素是否匹配
- 最后需要是空栈
java
class Solution {
// 思路:利用字符数组作栈
public boolean isValid(String s) {
char[] ch = s.toCharArray();
int top = 0;
for (int i = 0; i < ch.length; i++) {
char c = ch[i];
// 如果是左括号?进栈
if (isLeft(c)) {
ch[top++] = c;
} else {
// 如果是右括号?
// 首先栈内要有元素,检查跟栈顶元素是否匹配
if (top > 0 && isMatched(ch[top - 1], c)) {
// 匹配,出栈
top--;
} else {
// 不匹配,返回false
return false;
}
}
}
// 最后需要是空栈
return top == 0;
}
private boolean isLeft(char c) {
if (c == '(' || c == '{' || c == '[') {
return true;
} else {
return false;
}
}
private boolean isMatched(char a, char b) {
if (a == '(' && b == ')' || a == '[' && b == ']' || a == '{' && b == '}') {
return true;
} else {
return false;
}
}
}
思路:
使用stack库函数。其实大同小异。
java
class Solution {
// 思路:利用字符数组作栈
public boolean isValid(String s) {
char[] ch = s.toCharArray();
Deque<Character> stack = new ArrayDeque<>();
for (int i = 0; i < ch.length; i++) {
char c = ch[i];
// 如果是左括号?进栈
if (isLeft(c)) {
stack.push(c);
} else {
// 如果是右括号?
// 首先栈内要有元素,检查跟栈顶元素是否匹配
if (!stack.isEmpty() && isMatched(stack.peek(), c)) {
// 匹配,出栈
stack.pop();
} else {
// 不匹配,返回false
return false;
}
}
}
// 最后需要是空栈
return stack.isEmpty();
}
private boolean isLeft(char c) {
if (c == '(' || c == '{' || c == '[') {
return true;
} else {
return false;
}
}
private boolean isMatched(char a, char b) {
if (a == '(' && b == ')' || a == '[' && b == ']' || a == '{' && b == '}') {
return true;
} else {
return false;
}
}
}
思路:
使用switch case
java
class Solution {
public boolean isValid(String s) {
char[] ss = s.toCharArray();
Deque<Character> stack = new ArrayDeque<>();
for (char c : ss) {
switch(c){
case '(':
case '[':
case '{': stack.push(c);break;
case ')': if(stack.isEmpty()||stack.pop()!='(') return false;break;
case ']': if(stack.isEmpty()||stack.pop()!='[') return false;break;
case '}': if(stack.isEmpty()||stack.pop()!='{') return false;break;
}
}
return stack.isEmpty();
}
}