Leetcode刷题

秒速五厘米 2021-06-10 20:37 663阅读 0赞

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]
]

此题关键采用回溯算法解答

  1. class Solution {
  2. public List<List<Integer>> combinationSum(int[] candidates, int target) {
  3. //先从小到大排序,帮助去重与剪枝优化
  4. Arrays.sort(candidates);
  5. recursion(candidates,target,new ArrayList());
  6. return result;
  7. }
  8. List<List<Integer>> result = new ArrayList<>();
  9. public void recursion(int[] candidates,int target,int index,List<Integer> list){
  10. //如果target比candidates[index]还小了,没必要再进行下去了
  11. while(index < candidates.length && target >= candidates[index]){
  12. if(target == candidates[index]){
  13. //得出满足条件的集合
  14. list.add(candidates[index]);
  15. result.add(list);
  16. return;
  17. }else{
  18. //复制新集合保存结果避免对下一轮递归的影响
  19. List newList = new ArrayList(list);
  20. newList.add(candidates[index]);
  21. recursion(candidates,target - candidates[index],index,newList);
  22. }
  23. index++;
  24. }
  25. }
  26. }

v

40. 组合总和 II

给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。

candidates 中的每个数字在每个组合中只能使用一次。

说明:

  • 所有数字(包括目标数)都是正整数。
  • 解集不能包含重复的组合。

示例 1:

输入: candidates = [10,1,2,7,6,1,5], target = 8,
所求解集为:
[
[1, 7],
[1, 2, 5],
[2, 6],
[1, 1, 6]
]

示例 2:

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

此题还是采用回溯算法,难点在于要考虑结果集去重

  1. class Solution {
  2. List<List<Integer>> result = new ArrayList<>();
  3. public List<List<Integer>> combinationSum2(int[] candidates, int target) {
  4. Arrays.sort(candidates);
  5. recursion(candidates, target, 0, new ArrayList());
  6. return result;
  7. }
  8. public void recursion(int[] candidates, int target, int index, List<Integer> list) {
  9. int start = index;
  10. while (index < candidates.length && target >= candidates[index]) {
  11. //结果集去重
  12. if(index > start && candidates[index] == candidates[index - 1]){
  13. index++;
  14. continue;
  15. }
  16. if (target == candidates[index]) {
  17. list.add(candidates[index]);
  18. result.add(list);
  19. return;
  20. } else {
  21. List newList = new ArrayList(list);
  22. newList.add(candidates[index]);
  23. recursion(candidates, target - candidates[index], index + 1, newList);
  24. }
  25. index++;
  26. }
  27. }
  28. }

分苹果

题目:
果园里有一堆苹果,一共n头(n小于9且大于1)熊来分,第一头将苹果分为n份,多出一个扔掉,拿走其中一份,接着第二天熊重复这个过程,即先均分n份,丢掉多出的一个,然后拿走一份,依次类推直到最后一头熊都是这样(最后一头熊可以拿走0个也算均分)。问最初这堆苹果最少有多少个。

  1. public class AppleAlgorithm {
  2. private int n;
  3. public AppleAlgorithm(int n) throws Exception {
  4. if(n<2||n>8){
  5. throw new Exception("非法的个数");
  6. }
  7. this.n = n;
  8. }
  9. public int getN(){
  10. return n;
  11. }
  12. public boolean splitApple(int num, int apple) {
  13. if (num == 0) {
  14. return true;
  15. }else if(apple <= 0){
  16. return false;
  17. }
  18. if ((apple-1) % n == 0) {
  19. return splitApple(num - 1, (apple - 1) / n * (n - 1));
  20. } else {
  21. return false;
  22. }
  23. }
  24. public static void main(String[] args) throws Exception {
  25. int i = 1;
  26. AppleAlgorithm apple = new AppleAlgorithm(2);
  27. while (true) {
  28. if (apple.splitApple(apple.getN(), i)) {
  29. System.out.println("result = " + i);
  30. break;
  31. }
  32. i++;
  33. }
  34. }
  35. }

如题:输入正整数n,打印出1到10的n次方的值,如输入3,则输出1,2,3…,999.

看上去是一道很简单的题目,只要有点编程基础,我想大部分人都能写出如下代码:

  1. @Test
  2. public void test5() {
  3. printNumber(3);
  4. }
  5. public void printNumber(int n) {
  6. int num = 1;
  7. while (n-- > 0) {
  8. num *= 10;
  9. }
  10. for (int i = 1; i < num; i++) {
  11. System.out.print(i+" ");
  12. if (i % 10 == 0)
  13. System.out.println();
  14. }
  15. }

但是上述代码有个很隐晦的bug,那就是当n取值很大时,比如100,那么10^n这个值也就很大,明显会超过int最大值,就算换成long也依然会出问题,所以完美解法提供如下:

  1. @Test
  2. public void test4() {
  3. printNumber(10);
  4. }
  5. //这个值记录输出的值的个数
  6. int m = 0;
  7. public void pirntNumber(int n){
  8. int[] nums = new int[n];
  9. printNum(nums, n);
  10. System.out.println(" \n m = " + m);
  11. }
  12. //原理很简单,说白了就是递归而已。
  13. public void printNum(int[] nums, int n) {
  14. //要输出多少位的数值,就递归多少次
  15. if (n > 0) {
  16. n--;
  17. //数组由后往前依次存放要输出的数字的当前位数的值(从高到低)
  18. for (int i = 0; i < 10; i++) {
  19. nums[n] = i;
  20. printNum(nums, n);
  21. }
  22. } else {
  23. //当递归次数用尽,那么就开始打印这个数字,从高位到低位开始
  24. int k = nums.length - 1;
  25. /*下面这个循环是为了去掉无效的0,比如数组中依次存放的是应该是0,8,0,0,那么输出结果就应该是80.
  26. */
  27. while (nums[k] == 0) {
  28. k--;
  29. if (k < 0) {
  30. return;
  31. }
  32. }
  33. //每输出10个数换行
  34. if (m++ % 10 == 0) {
  35. System.out.println();
  36. }
  37. //从后往前输出数组中的数字,也就是输出10^n的值
  38. for (; k >= 0; k--) {
  39. System.out.print(nums[k]);
  40. }
  41. System.out.print(" ");
  42. return;
  43. }
  44. }

发表评论

表情:
评论列表 (有 0 条评论,663人围观)

还没有评论,来说两句吧...

相关阅读

    相关 LeetCode指南

    以下是我个人做题过程中的一些体会:  1. LeetCode的题库越来越大,截止到目前,已经有321个问题了。对于大多数人来说,没有时间也没有必要把所有题目都做一遍(时间充

    相关 Leetcode

    39. 组合总和 给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。