给一个int []整数数组,[2,7,3,5,3]会有重复值,现在给aim=10,组成10最少用多少个硬币?

    1. public static int coinsWay1(int[] arr, int aim) {
    2. if (arr == null || arr.length == 0 || aim < 0) {
    3. return 0;
    4. }
    5. return process1(arr, 0, aim);
    6. }
    7. // 暴力递归
    8. // arr[index...]组成rest这么多钱,最少的硬币数量返回。
    9. // arr硬币都在里面
    10. // index:自由选择arr[index...]
    11. // rest:剩余到达成的目标
    12. // 组成rest这么多钱,返回最少的硬币数
    13. public static int process1(int[] arr, int index, int rest) {
    14. if(rest < 0){
    15. return -1; // 代表到最后怎么都组成都组成不了
    16. }
    17. if(rest == 0){
    18. return 0; // 说明已经搞定了aim,需要0枚
    19. }
    20. // rest>0情况
    21. // index == arr.length 没有硬币了,没有这样的方案
    22. if(index == arr.length){
    23. return -1;
    24. }
    25. // rest>0,并且也有硬币
    26. // 不选择当前硬币,和选择当前硬币
    27. // 不选择index硬币
    28. int p1 = process1(arr, index + 1, rest);
    29. // 选择当前硬币
    30. int p2Next = process1(arr, index + 1, rest - arr[index]);
    31. if(p1 == -1 && p2Next == -1){
    32. return -1;
    33. }else{
    34. if(p1 == -1){ // 决策p1无效,返回p2 , +1是因为用了当前idnex硬币
    35. return p2Next + 1;
    36. }
    37. if(p2Next == -1){ // 决策p2无效,返回p1
    38. return p1;
    39. }
    40. return Math.min(p1, p2Next+1); // 都有效,决策选择出用的硬币最少的,无效解-1会干扰决策
    41. }
    42. // 不能这样,等于-1时会影响到决策
    43. // return Math.min(process1(arr, index + 1, rest),
    44. // 1 + process1(arr, index + 1, rest - arr[index]));
    45. }
    46. // 记忆化搜索,搞定可变参数组合
    47. public static int coinsWay2(int[] arr, int aim) {
    48. if (arr == null || arr.length == 0 || aim < 0) {
    49. return 0;
    50. }
    51. int [][] dp =new int [arr.length+1][aim+1];
    52. for (int i = 0; i <= arr.length; i++) {
    53. for (int j = 0; j <= aim; j++) {
    54. dp[i][j] = -2; //表示没计算过
    55. }
    56. }
    57. return process2(arr, 0, aim, dp);
    58. }
    59. // arr硬币都在里面
    60. // index:自由选择arr[index...]这些硬币
    61. // rest:剩余到达成的目标
    62. // 组成rest这么多钱,返回最少的硬币数
    63. public static int process2(int[] arr, int index, int rest,int[][] dp) {
    64. // 认为中了无效缓存
    65. if(rest<0){
    66. return -1; // 直接放前面,也算一种缓存
    67. }
    68. if(dp[index][rest]!= -2){
    69. return dp[index][rest];
    70. }
    71. if(rest==0){
    72. dp[index][rest]=0;
    73. }else if(index == arr.length){
    74. // rest>0,没有硬币
    75. dp[index][rest]=-1;
    76. }else{
    77. int p1 = process2(arr, index + 1, rest,dp);
    78. int p2Next = process2(arr, index + 1, rest - arr[index],dp);
    79. if(p1 == -1 && p2Next == -1){
    80. dp[index][rest]=-1;
    81. }else{
    82. if(p1 == -1){ // 决策p1无效,返回p2
    83. dp[index][rest]= p2Next + 1;
    84. }else if(p2Next == -1){ // 决策p2无效,返回p1
    85. dp[index][rest]= p1;
    86. }else{
    87. dp[index][rest]= Math.min(p1, p2Next+1); // 都有效,决策
    88. }
    89. }
    90. }
    91. return dp[index][rest];
    92. }
    93. // 动态规划
    94. public static int coinsWay3(int[] arr, int aim) {
    95. if (arr == null || arr.length == 0 || aim < 0) {
    96. return 0;
    97. }
    98. int N=arr.length;
    99. int [][] dp =new int [N+1][aim+1];
    100. // base case
    101. for (int row = 0; row <= N; row++) {
    102. dp[row][0]=0;
    103. }
    104. // base case
    105. for (int col = 1; col <= aim; col++) {
    106. dp[N][col] = -1;
    107. }
    108. // n行填好, 从n-1行开始,从左往右,从下向上
    109. for (int index = N-1; index >=0; index--) {
    110. // 0列填好,从开始
    111. for (int rest = 1; rest <= aim; rest++) {
    112. // 把递归代码黏贴过来改
    113. // 递归过程变成了,动态规划格子取值过程
    114. int p1 = dp[index+1][rest];
    115. int p2Next = -1; // 越界-1 ,没越界赋值,注意边界
    116. if(rest - arr[index]>=0){ // [rest - arr[index]]可能越界所以要这样写
    117. p2Next = dp[index+1][rest - arr[index]];
    118. }
    119. if(p1 == -1 && p2Next == -1){
    120. dp[index][rest] = -1;
    121. }else{
    122. if(p1 == -1){ // 决策p1无效,返回p2
    123. dp[index+1][rest]= p2Next + 1;
    124. }
    125. if(p2Next == -1){ // 决策p2无效,返回p1
    126. dp[index+1][rest]= p1;
    127. }
    128. dp[index+1][rest]= Math.min(p1, p2Next+1); // 都有效,决策 ,因为最后一行是-1还是有干扰
    129. }
    130. }
    131. }
    132. // 最终返回
    133. return dp[0][aim];
    134. }