题解 | #数组分组#
数组分组
https://www.nowcoder.com/practice/9af744a3517440508dbeb297020aca86
import java.util.Scanner;
import java.util.Stack;
public class Main {
public static void main(String[] args) {
//这道题的思想
System.out.println(fun());
}
public static boolean fun() {
Scanner in = new Scanner(System.in);
int m = in.nextInt();
int a = 0;
int b = 0;
int c = 0;
//事先将这两个分组
int[] n = new int[m];
Stack<Integer> stack = new Stack<>();
int sum_max = 0, offset = 0; //计算前后的偏移量
for (int i = 0; i < m; i++) {
n[i] = in.nextInt();
if (n[i] % 5 == 0) {
a += n[i];
} else if ( n[i] % 3 == 0) {
b += n[i];
} else {
stack.push(n[i]);
sum_max += Math.abs(n[i]);
//用于移位的
offset += n[i] >= 0 ? 0 : Math.abs(n[i]);
c += n[i];
}
}
//转为为背包问题 先将两个集合分类
//leetcode416 耐心复习
int s = b + c - a;
if (s % 2 != 0) return false;
if (stack.size() == 0) return s == 0;
if (stack.size()==1) return s==stack.peek()||s==-stack.peek(); //1
int tar = stack.size();
s /= 2;
//两个都要加个一作为缓冲
boolean[][] dp = new boolean[tar + 1][sum_max + 1];
int[] num = new int[tar];
for (int i = tar - 1; i >= 0 ; i--) {
num[i] = stack.pop();
}
//将dp数组处理的位置换个地方
//原来的初始化是有问题的 dp[0][0】 那个部分问题
dp[0][offset] = true;
for (int i = 1; i <= tar ; i++) {
int x = num[i - 1];
for (int j = sum_max; j >= 0; j--) { //有负的计算的时候看右上方
dp[i][j] = dp[i - 1][j];
if (j - x > sum_max || j - x < 0) continue;
dp[i][j] = dp[i - 1][j - x] || dp[i][j];
}
}
if(s + offset<0||s+offset>sum_max) return false; //2
return dp[tar][s + offset];
}
}
将题目转化为01背包做题,由于与416的区别在于此时可能为负数,需要便宜
416 的dp【i,0 】=true这一核心点,之后的根据这个同时对dp【0,offset】 之前的dp【i,0 】=true那个情况的转变,代码随想录的初始化方式有问题,建议看力扣官网。
C语言数组越界不报错,这里越界的话直接就是无解
还是去看递归的实现
查看20道真题和解析