LeetCode Top100之39,42,46题

    xiaoxiao2023-11-28  164

    写于2019年5月25日

    文章目录

    [39. 组合总和](https://leetcode.com/problems/combination-sum/)① 题目描述② 使用回溯法 [42. 接雨水](https://leetcode.com/problems/trapping-rain-water/)① 题目描述② 暴力法(按列遍历)③ 使用堆栈 [46. 全排列](https://leetcode.com/problems/permutations/)① 题目描述② 回溯法③ 交换法(实质回溯,`Hot`)④ 带重复数字的全排列——[leetcode的47题](https://leetcode.com/problems/permutations-ii/)

    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); } } }
    最新回复(0)