代码随想录算法训练营第四十一天 | hot65/100| 33.搜索旋转排序数组、153.寻找旋转排序数组中的最小值、155.最小栈、394.字符串解码

33.搜索旋转排序数组

思路是:

数组可能有两种情况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;
    }
}

153.寻找旋转排序数组中的最小值

思路是:

旋转后的数组一定被分成了前后两部分且两半都是升序数组,且前一半的最小值一定大于后一半的最大值,**只要用二分找到后一半的第一个元素即可**

完整代码:
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]看看

155.最小栈

思路是:

我们只需要设计一个数据结构,使得每个元素 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();
    }
}

394.字符串解码

字符串的问题,麻烦的就是各种细节,toString()之类的来回变换要注意

思路是:

代码随想录算法训练营第四十一天 | hot65/100| 33.搜索旋转排序数组、153.寻找旋转排序数组中的最小值、155.最小栈、394.字符串解码_第1张图片


 完整代码:
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 stack = new Stack();
而不是deque stack = new deque();

新建可拼接字符串:
StringBuilder sb = new StringBuilder();
而不是StringBuilder sb = new StringBuilder<>();
    


 

你可能感兴趣的:(刷题,算法,leetcode,数据结构)