博客记录-day147-力扣

101 阅读2分钟

一、力扣

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

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

image.png

class Solution {
    public int[] searchRange(int[] nums, int target) {
        int start = lowerBound(nums, target);
        if (start == nums.length || nums[start] != target) {
            return new int[]{-1, -1}; // nums 中没有 target
        }
        // 如果 start 存在,那么 end 必定存在
        int end = lowerBound(nums, target + 1) - 1;
        return new int[]{start, end};
    }

    // lowerBound 返回最小的满足 nums[i] >= target 的下标 i
    // 如果数组为空,或者所有数都 < target,则返回 nums.length
    // 要求 nums 是非递减的,即 nums[i] <= nums[i + 1]
    private int lowerBound(int[] nums, int target) {
        int left = 0;
        int right = nums.length; // 左闭右开区间 [left, right)
        while (left < right) { // 区间不为空
            // 循环不变量:
            // nums[left-1] < target
            // nums[right] >= target
            int mid = left + (right - left) / 2;
            if (nums[mid] >= target) {
                right = mid; // 范围缩小到 [left, mid)
            } else {
                left = mid + 1; // 范围缩小到 [mid+1, right)
            }
        }
        // 循环结束后 left = right
        // 此时 nums[left-1] < target 而 nums[left] = nums[right] >= target
        // 所以 left 就是第一个 >= target 的元素下标
        return left;
    }
}

2、字符串解码

394. 字符串解码

image.png

class Solution {
    public String decodeString(String s) {
        // 使用两个栈分别保存数字和字符串片段
        ArrayDeque<Integer> stnum = new ArrayDeque<>();  // 存储重复次数
        ArrayDeque<StringBuilder> stsb = new ArrayDeque<>(); // 存储之前的字符串结果
        StringBuilder ans = new StringBuilder(); // 当前构建的字符串
        int k = 0; // 临时存储当前处理的数字

        for (int i = 0; i < s.length(); i++) {
            char temp = s.charAt(i);
            
            if (Character.isDigit(temp)) {
                // 处理多位数字,例如将 '12' 转换为整数12
                k = k * 10 + (temp - '0');
            } else if (temp == '[') {
                // 遇到左括号,保存当前状态到栈中
                stnum.push(k);       // 保存当前重复次数
                stsb.push(ans);      // 保存当前已构建的字符串
                k = 0;               // 重置数字计数器
                ans = new StringBuilder(); // 清空当前字符串,准备处理括号内内容
            } else if (temp == ']') {
                // 遇到右括号,弹出栈顶元素拼接结果
                int count = stnum.pop();   // 获取重复次数
                StringBuilder col = stsb.pop(); // 获取之前的字符串片段
                
                // 将当前括号内的内容重复count次并拼接到col
                while (count > 0) {
                    col.append(ans);
                    count--;
                }
                ans = col; // 更新ans为拼接后的结果
            } else {
                // 普通字符直接追加到当前结果
                ans.append(temp);
            }
        }
        return ans.toString();
    }
}

3、子集

78. 子集

image.png

class Solution {
    List<List<Integer>> res;
    List<Integer> path;
    int[] nums;
    public List<List<Integer>> subsets(int[] nums) {
        res=new ArrayList<>();
        path=new ArrayList<>();
        this.nums=nums;
        dfs(0);
        return res;
    }
    public void dfs(int start){
        res.add(new ArrayList<>(path));
        for(int i=start;i<nums.length;i++){
            path.add(nums[i]);
            dfs(i+1);
            path.removeLast();
        }
    }
}

4、子集 II

90. 子集 II

image.png

class Solution {
    List<List<Integer>> res;
    List<Integer> path;
    int[] nums;
    public List<List<Integer>> subsetsWithDup(int[] nums) {
        res=new ArrayList<>();
        path=new ArrayList<>();
        Arrays.sort(nums);
        this.nums=nums;
        int[] vis=new int[nums.length];
        dfs(0,vis);
        return res;
    }
    public void dfs(int start,int[] vis){
        res.add(new ArrayList<>(path));
        for(int i=start;i<nums.length;i++){
            if(i>0&&nums[i]==nums[i-1]&&vis[i-1]==0) continue;
            path.add(nums[i]);
            vis[i]=1;
            dfs(i+1,vis);
            path.removeLast();
            vis[i]=0;
        }
    }
}

5、非递减子序列

491. 非递减子序列

image.png

class Solution {
    List<List<Integer>> res;
    List<Integer> path;
    int[] nums;
    int n;
    public List<List<Integer>> findSubsequences(int[] nums) {
        n=nums.length;
        res=new ArrayList<>();
        path=new ArrayList<>();
        this.nums=nums;
        backtracking(0);
        return res;
    }
    public void backtracking(int start){
        if(path.size()>=2){
            res.add(new ArrayList<>(path));
        }
        Set<Integer> set=new HashSet<>();
        for(int i=start;i<n;i++){
            if(path.size()>0&&nums[i]<path.get(path.size()-1)) continue;
            if(set.contains(nums[i])) continue;
            set.add(nums[i]);
            path.add(nums[i]);
            backtracking(i+1);
            path.removeLast();
        }
    }
}