Zzhaozhao的刷算法之路-第一周

52 阅读7分钟

1.二分法

1.1.题目一:二分查找(力扣704题)

  1. 题目描述:给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。

  2. 示例 :

    示例 1:
    输入: nums = [-1,0,3,5,9,12], target = 9
    输出: 4
    解释: 9 出现在 nums 中并且下标为 4
    ​
    示例 2:
    输入: nums = [-1,0,3,5,9,12], target = 2
    输出: -1
    解释: 2 不存在 nums 中因此返回 -1
    
  1. 思路:设置两个左右指针分别为数组两个边界,然后取中间值再与n比较一共有三种情况

    1. 第一种:中间值等于n,直接返回n;
    2. 第二种:中间值大于n,将右边界赋值为中间值减一,再次计算中间值再进行比较;
    3. 第三种:n小于中间值,将左边界赋值为中间值加一,再次计算中间值再进行比较。
  1. 代码如下:

    class Solution {
        public int search(int[] nums, int target) {
            int left = 0, right = nums.length - 1;
            
            while(left <= right){
                // 向下取整
                int mid = left + (right - left) / 2;
                if(nums[mid] == target){
                    return mid;
                }else if (nums[mid] > target){
                   right = mid - 1;
                }else {
                   left = mid + 1;
                }
            }
            return -1;
        }
    }
    

1.2.题目二:猜数字大小(力扣374题)

  1. 题目描述:我们正在玩猜数字游戏。猜数字游戏的规则如下:我会从 1 到 n 随机选择一个数字。 请你猜选出的是哪个数字。如果你猜错了,我会告诉你,我选出的数字比你猜测的数字大了还是小了。你可以通过调用一个预先定义好的接口 int guess(int num) 来获取猜测结果,返回值一共有三种可能的情况:

    1. -1:你猜的数字比我选出的数字大 (即 num > pick)。
    2. 1:你猜的数字比我选出的数字小 (即 num < pick)。
    3. 0:你猜的数字与我选出的数字相等。(即 num == pick)。 返回我选出的数字。
  1. 示例 :

    示例 1:
    输入:n = 10, pick = 6
    输出:6
    输入:n = 1, pick = 1
    输出:1
    示例 3:
    输入:n = 2, pick = 1
    输出:1
    
  1. 思路:思路同上,通过接口返回的数字来判断猜的数字是大了还是小了,如果相等直接返回中间值,不再赘述。
  1. 代码如下:

    /** 
     * Forward declaration of guess API.
     * @param  num   your guess
     * @return       -1 if num is higher than the picked number
     *            1 if num is lower than the picked number
     *               otherwise return 0
     * int guess(int num);
     */
    ​
    public class Solution extends GuessGame {
        public int guessNumber(int n) {
            int left = 1 , right = n;
            while(left <= n){
                int mid = left + (right - left) / 2;
                int result = guess(mid);
                if(result == 0){
                    return mid;
                }else if(result == -1){
                    right = mid - 1;
                }else{
                    left = mid + 1;
                }
            }
            return -1;
        }
    }
    

1.3.搜索插入位置

  1. 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

  2. 示例:

    示例 1:
    输入: nums = [1,3,5,6], target = 5
    输出: 2
    ​
    示例 2:
    输入: nums = [1,3,5,6], target = 2
    输出: 1
    ​
    示例 3:
    输入: nums = [1,3,5,6], target = 7
    输出: 4
    
  3. 代码如下

    class Solution {
        public int searchInsert(int[] nums, int target) {
            int left = 0, right = nums.length - 1;
            while(left <= right){
                int mid = (right + left) / 2;
                if(nums[mid] == target){
                    return mid;
                }else if (nums[mid] > target){
                    right = mid - 1;
                }else {
                    left = mid + 1;
                }
            }
            return left;
        }
    }
    
  4. 力扣大佬模版

    class Solution {
        public int searchInsert(int[] nums, int target) {
            int left = 0, right = nums.length - 1; // 注意
            while(left <= right) { // 注意
                int mid = (left + right) / 2; // 注意
                if(nums[mid] == target) { // 注意
                    // 相关逻辑
                } else if(nums[mid] < target) {
                    left = mid + 1; // 注意
                } else {
                    right = mid - 1; // 注意
                }
            }
            // 相关返回值
            return 0;
        }
    }
    ​
    ​
    class Solution {
        public int searchInsert(int[] nums, int target) {
            int left = 0, right = nums.length; // 注意
            while(left < right) { // 注意
                int mid = (left + right) / 2; // 注意
                if(nums[mid] == target) {
                    // 相关逻辑
                } else if(nums[mid] < target) {
                    left = mid + 1; // 注意
                } else {
                    right = mid; // 注意
                }
            }
            // 相关返回值
            return 0;
        }
    }
    ​
    作者:画手大鹏
    链接:https://leetcode.cn/problems/search-insert-position/solutions/8017/hua-jie-suan-fa-35-sou-suo-cha-ru-wei-zhi-by-guanp/
    来源:力扣(LeetCode)
    

    2.1.有效括号

    1. 问题描述:

      1. 给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。

      2. 有效字符串需满足:

        1. 左括号必须用相同类型的右括号闭合。
        2. 左括号必须以正确的顺序闭合。
        3. 每个右括号都有一个对应的相同类型的左括号。
      示例 1:
      输入:s = "()"
      输出:true
      ​
      示例 2:
      输入:s = "()[]{}"
      输出:true
      ​
      示例 3:
      输入:s = "(]"
      输出:false
      
    2. 思路:

      1. 新建一个哈希表,并且把符号放进去,为了防止栈为空报错,提前放入问号,如果长度小于1或者符号不存在直接返回
      2. 新建一个队列,提前放入一个问号
      3. 遍历字符串,如果字符串包含就压入栈中 如果删除的元素在哈希表中不存在那么就返回false
      4. 如果全部存在,那么栈只剩下问号
    3. 代码实现

      class Solution {
          private static final Map<Character,Character> map = new HashMap<Character,Character>(){{
              put('{','}'); put('[',']'); put('(',')'); put('?','?');
          }};
          public boolean isValid(String s) {
              if(s.length() < 0 || !map.containsKey(s.charAt(0))){
                  return false;
              }
              LinkedList<Character> stack = new LinkedList<Character>();
              stack.add('?');
      ​
              for(Character c : s.toCharArray()){
                  if(map.containsKey(c)){
                      stack.addLast(c);
                  }
                // 顶部元素不存在就为false
                else if(map.get(stack.removeLast()) != c){
                      return false;
                  }
              }
              return stack.size() ==1;
      ​
          }
      }
      

    2.2.最小栈

    1. 题目:

      1. 请你设计一个 最小栈 。它提供 pushpoptop 操作,并能在常数时间内检索到最小元素的栈。实现 MinStack 类:

        1. MinStack() 初始化堆栈对象。
        2. void push(int val) 将元素val推入堆栈。
        3. void pop() 删除堆栈顶部的元素。
        4. int top() 获取堆栈顶部的元素。
        5. int getMin() 获取堆栈中的最小元素。
      2. 示例:

        示例 1:
        输入:
        ["MinStack","push","push","push","getMin","pop","top","getMin"]
        [[],[-2],[2],[-3],[],[],[],[]]
        
        输出:
        [null,null,null,null,-3,null,2,-2]
        
        解释:
        MinStack minStack = new MinStack();
        minStack.push(-2);
        minStack.push(2);
        minStack.push(-3);
        minStack.getMin();   --> 返回 -3.
        minStack.pop();
        minStack.top();      --> 返回 2.
        minStack.getMin();   --> 返回 -2.
        
      3. 思路:

        1. 设置一个辅助栈,用来存取非严格递减的数据
        2. push:当向栈里压数据的时候,首先直接压入A里面,如果B是空的,或者B的peek()的值小于要压入的值,才压入B中
        3. getMin:直接获取B栈顶的数据
        4. pop:直接弹出A栈的数据,并且如果弹出的数据与B的栈顶相同,B也弹出
        5. top:直接获取B得栈顶
      4. 代码如下:

        class MinStack {
            Stack<Integer> A,B;
            /** initialize your data structure here. */
            public MinStack() {
                A = new Stack<>();
                B = new Stack<>();
            }
            
            public void push(int x) {
                A.add(x);
                if(B.empty() || B.peek() >= x ){
                    B.add(x);
                }
            }
            
            public void pop() {
                
                if(A.pop().equals(B.peek())){
                    B.pop();
                }
            }
            
            public int top() {
                return A.peek();
            }
            
            public int getMin() {
                return B.peek();
            }
        }
        
        /**
         * Your MinStack object will be instantiated and called as such:
         * MinStack obj = new MinStack();
         * obj.push(x);
         * obj.pop();
         * int param_3 = obj.top();
         * int param_4 = obj.getMin();
         */
        
    2. 题目:

      1. 给你一个字符串数组 tokens ,表示一个根据 逆波兰表示法 表示的算术表达式。请你计算该表达式。返回一个表示表达式值的整数

      2. 有效的算符为 '+''-''*''/' 。每个操作数(运算对象)都可以是一个整数或者另一个表达式。

      3. 两个整数之间的除法总是 向零截断

      4. 表达式中不含除零运算。

      5. 输入是一个根据逆波兰表示法表示的算术表达式。

      6. 答案及所有中间计算结果可以用 32 位 整数表示。

    3. 示例:

             示例 1:
             输入:tokens = ["2","1","+","3","*"]
             输出:9
             解释:该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9
               
             示例 2:
             输入:tokens = ["4","13","5","/","+"]
             输出:6
             解释:该算式转化为常见的中缀算术表达式为:(4 + (13 / 5)) = 6
               
             示例 3:
             输入:tokens = ["10","6","9","3","+","-11","*","/","*","17","+","5","+"]
             输出:22
             解释:该算式转化为常见的中缀算术表达式为:
               ((10 * (6 / ((9 + 3) * -11))) + 17) + 5
             = ((10 * (6 / (12 * -11))) + 17) + 5
             = ((10 * (6 / -132)) + 17) + 5
             = ((10 * 0) + 17) + 5
             = (0 + 17) + 5
             = 17 + 5
             = 22
             ```
      
      
    4. 思路:

      1. 逆波兰表达式就是后缀表达式,平时用的最多的就是中值表达式(1+1),后缀表达式就是(1 1 +)
      2. 逆波兰表达式就是树的后序遍历
      3. 用栈来做首先创建栈,判断字符是否是是数字,如果是就压入栈中,如果不是那么就取出栈顶的两个元素后取出来的和运算符然后是先取出来的元素进行运算,再压回栈里
      4. 最后获取到栈顶元素就是最后的结果
    5. 代码

              class Solution {
                  public int evalRPN(String[] tokens) {
                      Stack<Integer> stack = new Stack<>();
                      int n = tokens.length;
                      for(int i = 0; i < n; i++){
                          String token = tokens[i];
                          if(isNumer(token)){
                              stack.push(Integer.parseInt(token));
                          }else{
                              int num2 = stack.pop();
                              int num1 = stack.pop();
              ​
                              switch(token){
                                  case"+":
                                      stack.push(num1 + num2);
                                      break;
                                  case"-":
                                      stack.push(num1 - num2);
                                      break;
                                  case"*":
                                      stack.push(num1 * num2);
                                      break;
                                  case"/":
                                      stack.push(num1 / num2);
                                      break;
                                  default:
                              }
                          }
                      }
                      return stack.pop();
                  }
              ​
                  public boolean isNumer(String token){
                      return !("+".equals(token) || "-".equals(token) || "*".equals(token) || "/".equals(token));
                  }
              }
              ```