前言

本文隶属于专栏《LeetCode 刷题汇总》,该专栏为笔者原创,引用请注明来源,不足和错误之处请在评论区帮忙指出,谢谢!

本专栏目录结构请见LeetCode 刷题汇总

正文

幕布

在这里插入图片描述

幕布链接

31. 下一个排列

题解

下一个排列算法详解:思路+推导+步骤,看不懂算我输!

后->前,找第一个连续降序前一个数字,然后二分查找刚好比它大的,交换,降序改升序

class Solution {
    public void nextPermutation(int[] nums) {
        int n = 0;
        if(nums == null || (n = nums.length) == 0)  return;
        // 从后往前查找第一次出现 nums[i] < nums[i+1] 的位置
        int i = n-2;
        for(; i>=0 && nums[i] >= nums[i+1]; i--)    ;
        // if i == -1 nums 则整体逆序
        if(i >= 0){
            // 此时 nums[i+1, n-1] 降序, 查找其中 大于nums[i] 的最大下标,可以直接 从后往前 逆向找
            // 因为有序 可以练习一下二分查找
            int j = binarySearch(nums, i+1, n-1, nums[i]);
            // 交换 i j
            swap(nums, i, j);
        }
        // 此时 nums[i+1, n-1] 仍然降序,将其改为升序,只需要反转即可。
        reverse(nums, i+1, n-1);
    }

    // nums[left, right] 逆序,查找其中 > target 的 最大下标
    private int binarySearch(int[] nums, int left, int right, int target){
        while(left <= right){
            int mid = (left + right) >>> 1;
            if(nums[mid] > target){
                left = mid + 1; // 尝试再缩小区间
            }else{
                right = mid - 1;
            }
        }
        return right;
    }

    private void swap(int[] nums, int i, int j){
        int tmp = nums[i];
        nums[i] = nums[j];
        nums[j] = tmp;
    }

    private void reverse(int[] nums, int i, int j){
        while(i < j){
            swap(nums, i++, j--);
        }
    }
}

32. 最长有效括号

题解

官方题解

动态规划,字符串中对应的索引为有效子串结尾的最长有效括号子串的长度

object Solution {
  def longestValidParentheses(s: String): Int = {
    if (s.isEmpty) return 0
    val n = s.length
    //dp 表示 s 中对应的索引为有效子串结尾的最长有效括号子串的长度
    val dp = new Array[Int](n)
    for (i <- 1 until n) {
      if (s(i) == '(') dp(i) = 0
      else {
        if (s(i - 1) == '(') dp(i) = if (i > 2) dp(i - 2) + 2 else 2
        else if (i - dp(i - 1) - 1 >= 0 && s(i - dp(i - 1) - 1) == '(') dp(i) = dp(i - 1) + 2 + (if (i - dp(i - 1) - 2 >= 0) dp(i - dp(i - 1) - 2) else 0)
        else dp(i) = 0
      }
    }
    dp.max
  }
}

33. 搜索旋转排序数组

题解

官方题解

二分查找,先判断在中间

class Solution {
    public int search(int[] nums, int target) {
        if (nums == null || nums.length == 0) {
            return -1;
        }
        int start = 0, end = nums.length - 1, mid;
        while (start < end) {
            mid = start + ((end - start) >> 1);
            if (target == nums[mid]) {
                return mid;
            }
            if (nums[start] <= nums[mid]) {
                if (target >= nums[start] && target < nums[mid]) {
                    end = mid - 1;
                } else {
                    start = mid + 1;
                }
            } else {
                if (target > nums[mid] && target <= nums[end]) {
                    start = mid + 1;
                } else {
                    end = mid - 1;
                }
            }
        }
        return nums[start] == target ? start : -1;
    }
}

34. 在排序数组中查找元素的第一个和最后一个位置

题解

【动画模拟】一文带你搞定二分查找及其多个变种

二分查找,helper(nums, target + 1) - 1

class Solution {
    public int[] searchRange(int[] nums, int target) {
        int first = helper(nums, target);
        if(first == nums.length || nums[first] != target) return new int[]{-1, -1}; 
        return new int[]{first, helper(nums, target + 1) - 1};
    }

    private int helper(int[] nums, int target){
        int low = 0, high = nums.length;
        while(low < high){
            int mid = low + ((high - low) >> 1);
            if(nums[mid] < target) low = mid + 1;
            else high = mid;
        }
        return high;
    }
}

35. 搜索插入位置

题解

官方题解

标准二分

object Solution {
  def searchInsert(nums: Array[Int], target: Int): Int = {
    val n = nums.length
    var low, mid = 0
    var high = n - 1
    while (low <= high) {
      mid = low + ((high - low) >> 1)
      if (nums(mid) == target) return mid
      else if (nums(mid) > target) high = mid - 1
      else low = mid + 1
    }
    low
  }
}
上一篇 下一篇