LeetCode Top100之39,42,46题

39. 组合总和

① 题目描述
  • 给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为
    target 的组合。
  • candidates 中的数字可以无限制重复被选取。
  • 说明:
    所有数字(包括 target)都是正整数。
    解集不能包含重复的组合。
  • 示例 1:

输入: candidates = [2,3,6,7], target = 7,
所求解集为: [ [7], [2,2,3] ]

  • 示例 2:

输入: candidates = [2,3,5], target = 8,
所求解集为: [ [2,2,2,2], [2,3,3], [3,5] ]

② 使用回溯法
  • 示例2为例,第一次加入了2,还可以加入2,直到里面的数字总和>= target。如果等于target将其加入result中,否则直接返回。返回之后,删除最后一个2,尝试添加下一个数字3。
  • 总体感觉: 回溯,就是向前走不动了,我就撤销最后一步继续向前,直到遍历完所有的结果。
  • 注意: 向result中添加一个结果时,要new ArrayList<>(temp),否则添加的仍然为temp所指向的内存,导致最后结果为[ [], [] ](以示例1为例)。
  • 代码如下:
List<List<Integer>> result = new ArrayList<>();
public List<List<Integer>> combinationSum(int[] candidates, int target) {
    
    
    backtrace(new ArrayList<>(), 0, target, candidates);
    return result;

}

public void backtrace(List<Integer> temp, int start, int remain, int[] nums) {
    
    
    if (remain < 0) {
    
    
        return;
    }
    if (remain == 0) {
    
    
        result.add(new ArrayList<>(temp));  // 一定要new!!!
        return;
    }
    for (int i = start; i < nums.length; i++) {
    
    
        temp.add(nums[i]);
        backtrace(temp, i, remain - nums[i], nums);
        temp.remove(temp.size() - 1);
    }
}

42. 接雨水

① 题目描述
  • 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
    在这里插入图片描述
  • 示例:

输入: [0,1,0,2,1,0,1,3,2,1,2,1]
输出: 6

② 暴力法(按列遍历)
  • 当前列能接水,由左边最高列、右边最高列的较小值减去当前列的高度决定(木桶原理)。
  • 如果左边最高列、右边最高列的较小值小于当前列的高度,直接置为0,否则为二者的差值。
  • 示意图如下,计算周围的列高度小于左右最高列的较小值,由于有另一较高列的支持,该行还是装Math.min(max_left, max_right) - height[i]的雨水:
    在这里插入图片描述
  • 代码如下:
public int trap(int[] height) {
    
    
    int size = height.length;
    int sum = 0;
    // 不用考虑第一列和最后一列,因为他们分别没有左边最高列、右边最高列
    for (int i = 1; i < size - 1; i++) {
    
    
        int max_left = 0, max_right = 0;
        // 找左边最高列
        for (int j = i - 1; j >= 0; j--) {
    
    
            if (max_left < height[j]) {
    
    
                max_left = height[j];
            }
        }
        // 找右边最高列
        for (int j = i + 1; j < size; j++) {
    
    
            if (max_right < height[j]) {
    
    
                max_right = height[j];
            }
        }
        int min = Math.min(max_left, max_right);
        // 如果最高列较小值小于当前列的高度,要设置接雨水的量为0
        sum += (min - height[i] > 0) ? (min - height[i]) : 0;
    }
    return sum;
}
③ 使用堆栈
  • 具体分析见博客,代码如下:
public int trap(int[] height) {
    
    
    int sum = 0;
    int current = 0;
    Stack<Integer> stack = new Stack<>();
    while (current < height.length) {
    
    
        //如果栈不空并且当前指向的高度大于栈顶高度就一直循环
        while (!stack.isEmpty() && height[current] > height[stack.peek()]) {
    
    
            int h = height[stack.peek()]; //取出要出栈的元素
            stack.pop();
            if (stack.isEmpty()) {
    
    // 栈空退出循环
                break;
            }
            int dis = current - stack.peek() - 1;//两堵墙之间的距离。
            int min = Math.min(height[stack.peek()], height[current]);
            sum = sum + dis * (min - h);
        }
        stack.push(current);//当前指向的墙入栈
        current++; //指针后移
    }
    return sum;
}

46. 全排列

① 题目描述
  • 给定一个没有重复数字的序列,返回其所有可能的全排列。
  • 示例:

输入: [1,2,3]
输出: [ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1] ]

② 回溯法
  • 当temp中含有当前元素时,则继续下一次循环,保证添加的元素不重复。
  • 当temp构造完成,返回,删除一次temp中刚添加的元素。
  • 代码如下:
public List<List<Integer>> permute(int[] nums) {
    
    
    List<List<Integer>> result = new ArrayList<>();
    backtrace(result, new ArrayList<>(), nums);
    return result;
}

public void backtrace(List<List<Integer>> result, List<Integer> temp, int[] nums) {
    
    
    if (temp.size() == nums.length) {
    
    
        result.add(new ArrayList<>(temp));
        return;
    }
    for (int i = 0; i < nums.length; i++) {
    
    
        if (temp.contains(nums[i])) {
    
    
            continue;
        }
        temp.add(nums[i]);
        backtrace(result, temp, nums);
        temp.remove(temp.size() - 1);
    }
}
③ 交换法(实质回溯,Hot
  • 代码如下:
public List<List<Integer>> permute(int[] nums) {
    
    
    List<List<Integer>> result = new ArrayList<>();
    helper(result, nums, 0);
    return result;
}

public void helper(List<List<Integer>> result, int[] nums, int current) {
    
    
    if (current == nums.length) {
    
    
        List<Integer> temp = new ArrayList<>();
        for (int i = 0; i < nums.length; i++) {
    
    
            temp.add(nums[i]);
        }
        result.add(temp);
    }
    for (int i = current; i < nums.length; i++) {
    
    
        swap(nums, i, current);
        helper(result, nums, current + 1);
        swap(nums, i, current);
    }
}

public void swap(int[] nums, int i, int j) {
    
    
    int temp = nums[i];
    nums[i] = nums[j];
    nums[j] = temp;
}
④ 带重复数字的全排列——leetcode的47题
  • 通过hashSet存储数字,如果是重复数字则不进行全排序。
public void helper(List<List<Integer>> result, int[] nums, int current) {
    
    
    if (current == nums.length) {
    
    
        List<Integer> temp = new ArrayList<>();
        for (int i = 0; i < nums.length; i++) {
    
    
            temp.add(nums[i]);
        }
        result.add(temp);
    }
    Set<Integer> set=new HashSet<>();
    for (int i = current; i < nums.length; i++) {
    
    
        if(!set.contains(nums[i])){
    
    
            set.add(nums[i]);
            swap(nums, i, current);
            helper(result, nums, current + 1);
            swap(nums, i, current);
        }
    }
}

猜你喜欢

转载自blog.csdn.net/u014454538/article/details/90552512