1.拆分数组 给定一个正整数组 arr,将 arr 中所有的数分成两个集合,尽量让两个集合的累加和接近。 返回最近情况下,较小集合的累计和。
暴力递归 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 public static int right (int [] arr) { if (arr == null || arr.length < 2 ) { return 0 ; } int sum = 0 ; for (int num : arr) { sum += num; } return process(arr, 0 , sum / 2 ); } public static int process (int [] arr, int index, int rest) { if (index == arr.length) { return 0 ; } else { int p1 = process(arr, index + 1 , rest); int p2 = 0 ; if (arr[index] <= rest) { p2 = arr[index] + process(arr, index + 1 , rest - arr[index]); } return Math.max(p1, p2); } }
动态规划 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public static int dp (int [] arr) { if (arr == null || arr.length < 2 ) { return 0 ; } int sum = 0 ; for (int num : arr) { sum += num; } sum /= 2 ; int N = arr.length; int [][] dp = new int [N + 1 ][sum + 1 ]; for (int i = N - 1 ; i >= 0 ; i--) { for (int rest = 0 ; rest <= sum; rest++) { int p1 = dp[i + 1 ][rest]; int p2 = 0 ; if (arr[i] <= rest) { p2 = arr[i] + dp[i + 1 ][rest - arr[i]]; } dp[i][rest] = Math.max(p1, p2); } } return dp[0 ][sum]; }
2.拆分数组2 给定一个正数数组 arr,把 arr 中的所有数分为两个集合。
要求:
如果 arr 长度为偶数,两个集合包含的个数要一样多
如果 arr 长度为奇数,两个集合包含的个数必须要差一个
两个集合的累计和尽可能接近
返回最接近情况下,较小集合的累加和。
暴力递归 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 public static int right (int [] arr) { if (arr == null || arr.length < 2 ) { return 0 ; } int sum = 0 ; for (int num : arr) { sum += num; } if ((arr.length & 1 ) == 0 ) { return process(arr, 0 , arr.length / 2 , sum / 2 ); } else { return Math.max(process(arr, 0 , arr.length / 2 , sum / 2 ), process(arr, 0 , arr.length / 2 + 1 , sum / 2 )); } } public static int process (int [] arr, int i, int picks, int rest) { if (i == arr.length) { return picks == 0 ? 0 : -1 ; } else { int p1 = process(arr, i + 1 , picks, rest); int p2 = -1 ; int next = -1 ; if (arr[i] <= rest) { next = process(arr, i + 1 , picks - 1 , rest - arr[i]); } if (next != -1 ) { p2 = arr[i] + next; } return Math.max(p1, p2); } }
动态规划 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 public static int dp (int [] arr) { if (arr == null || arr.length < 2 ) { return 0 ; } int sum = 0 ; for (int num : arr) { sum += num; } sum /= 2 ; int N = arr.length; int M = (N + 1 ) / 2 ; int [][][] dp = new int [N + 1 ][M + 1 ][sum + 1 ]; for (int i = 0 ; i <= N; i++) { for (int j = 0 ; j <= M; j++) { for (int k = 0 ; k <= sum; k++) { dp[i][j][k] = -1 ; } } } for (int rest = 0 ; rest <= sum; rest++) { dp[N][0 ][rest] = 0 ; } for (int i = N - 1 ; i >= 0 ; i--) { for (int picks = 0 ; picks <= M; picks++) { for (int rest = 0 ; rest <= sum; rest++) { int p1 = dp[i + 1 ][picks][rest]; int p2 = -1 ; int next = -1 ; if (picks - 1 >= 0 && arr[i] <= rest) { next = dp[i + 1 ][picks - 1 ][rest - arr[i]]; } if (next != -1 ) { p2 = arr[i] + next; } dp[i][picks][rest] = Math.max(p1, p2); } } } if (arr.length % 2 == 0 ) { return dp[0 ][arr.length / 2 ][sum]; } else { return Math.max(dp[0 ][arr.length / 2 ][sum], dp[0 ][(arr.length / 2 ) + 1 ][sum]); } }
3.N皇后问题(无法改动态规划) N皇后问题:在 N * N 的棋盘上要摆 N 个皇后,要求任何两个皇后不同行、不同列,也不在同一条斜线上。
给定一个整数 N,返回 N 皇后问题有多少种摆法。
N=1,返回1 N=2或3,2皇后和3皇后问题无论怎么摆都不行,返回0 N=8,返回92
暴力递归 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 public static int num (int n) { if (n < 1 ) { return 0 ; } int [] record = new int [n]; return process(0 , record, n); } public static int process (int i, int [] record, int n) { if (i == n) { return 1 ; } int res = 0 ; for (int j = 0 ; j < n; j++) { if (isValid(record, i, j)) { record[i] = j; res += process(i + 1 , record, n); } } return res; } public static boolean isValid (int [] record, int i, int j) { for (int k = 0 ; k < i; k++) { if (j == record[k] || Math.abs(record[k] - j) == Math.abs(i - k)) { return false ; } } return true ; }
暴力递归(位运算,常数时间优化) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 public static int num (int n) { if (n < 1 || n > 32 ) { return 0 ; } int limit = n == 32 ? -1 : (1 << n) - 1 ; return process(limit, 0 , 0 , 0 ); } public static int process (int limit, int colLim, int leftDiaLim, int rightDiaLim) { if (colLim == limit) { return 1 ; } int pos = limit & (~(colLim | leftDiaLim | rightDiaLim)); int mostRightOne = 0 ; int res = 0 ; while (pos != 0 ) { mostRightOne = pos & (~pos + 1 ); pos = pos - mostRightOne; res += process(limit, colLim | mostRightOne, (leftDiaLim | mostRightOne) << 1 , (rightDiaLim | mostRightOne) >>> 1 ); } return res; }