数组可能有两种情况2 3 4 5 6 7 1 和6 7 1 2 3 4 5
将数组一分为二,其中一定有一个是有序的,每次判断前半部分是有序的还是后半部分是有序的,每次只在有序的那部分里找。无序那部分不管(没找到会重新一分为二,继续在有序的一半里找,迟早会找到)
这道题重点是记住边界条件(哪些是小于等于 小于 大于等于 大于)
有小于等于/大于等于的情况是因为,如果出现[2, 1]中找1的情况,需要有等于
除了=target情况单独拿出来,其他都是有等于的(没有等于的都是=target被拿出来了)
class Solution {
public int search(int[] nums, int target) {
int left = 0;
int right = nums.length - 1;
while(left <= right){
int mid = left + (right - left)/2;
if(nums[mid] == target){
return mid;
}
// 前半部分有序,注意这里是小于等于
if(nums[left] <= nums[mid]){
// 第二个没有等于是如果等于就找到了
if(nums[left] <= target && target < nums[mid]){
right = mid - 1;
}else{
left = mid + 1;
}
// 后半部分有序
}else{
if(nums[mid] < target && target <= nums[right]){
left = mid + 1;
}else{
right = mid - 1;
}
}
}
return -1;
}
}
旋转后的数组一定被分成了前后两部分且两半都是升序数组,且前一半的最小值一定大于后一半的最大值,**只要用二分找到后一半的第一个元素即可**
public int findMin(int[] nums) {
// 1.min初始值为第一段升序数组的最小值,而且目前不知道数组是有两段升序还是只有一段升序
int min = nums[0];
// 2.先正常二分查找
int left = 0, right = nums.length - 1;
while(left <= right){
int mid = left + (right - left) / 2;
// 3.如果中间位置比min小,那么这个mid位置一定在第二段升序数组中,那么最小值一定在mid或者它的左边,这是因为每段都是升序的
// 先更新min,然后向左边遍历
if(nums[mid] < min){
min = nums[mid];
right = mid - 1;
}
// 4. 如果中间位置比min大,那么mid位置一定在第一段升序部分
// 所以直接向mid的右边遍历
else {
left = mid + 1;
}
}
return min;
}
一定是
if(nums[mid] < min){
}
else {
}
或者
if(nums[mid] >= min){
}
else {
}
依然是举例[2,1]看看
我们只需要设计一个数据结构,使得每个元素 a 与其相应的最小值 m 时刻保持一一对应。因此我们可以使用一个辅助栈,与元素栈同步插入与删除,用于存储与每个元素对应的最小值。
当一个元素要入栈时,我们取当前辅助栈的栈顶存储的最小值,与当前元素比较得出最小值,将这个最小值插入辅助栈中;
当一个元素要出栈时,我们把辅助栈的栈顶元素也一并弹出;
在任意一个时刻,栈内元素的最小值就存储在辅助栈的栈顶元素中。
class MinStack {
// minStack是辅助栈
Deque xStack;
Deque minStack;
public MinStack() {
xStack = new LinkedList();
minStack = new LinkedList();
minStack.push(Integer.MAX_VALUE);
}
public void push(int x) {
xStack.push(x);
minStack.push(Math.min(minStack.peek(), x));
}
public void pop() {
xStack.pop();
minStack.pop();
}
public int top() {
return xStack.peek();
}
public int getMin() {
return minStack.peek();
}
}
字符串的问题,麻烦的就是各种细节,toString()之类的来回变换要注意
public String decodeString(String s) {
Stack stack = new Stack<>();
for(char c : s.toCharArray())
{ // (1)
if(c != ']')
stack.push(c); // 把所有的字母push进去,除了]
else
{
// (2)
StringBuilder sb = new StringBuilder();
while(!stack.isEmpty() && Character.isLetter(stack.peek()))
sb.insert(0, stack.pop());
String sub = sb.toString();
stack.pop(); // 去除[
// (3)
sb = new StringBuilder();
while(!stack.isEmpty() && Character.isDigit(stack.peek()))
sb.insert(0, stack.pop());
int count = Integer.valueOf(sb.toString()); //倍数
// (4)
while(count > 0)
{
for(char ch : sub.toCharArray())
stack.push(ch);
count--;
}
}
}
//把栈里面所有的字母取出来
StringBuilder retv = new StringBuilder();
while(!stack.isEmpty())
retv.insert(0, stack.pop());
return retv.toString();
}
遍历字符串s里的每个字符:
for(char c : s.toCharArray())
转为字符串:
sub = sb.toString()
检查字符是不是字母/数字:
Character.isLetter(...)
Character.isDigit(...)
在字符串位置为0的地方插入...:
sb.insert(0, ...);
新建栈:
Stack
而不是deque
新建可拼接字符串:
StringBuilder sb = new StringBuilder();
而不是StringBuilder sb = new StringBuilder<>();