题解 | #数组分组#
数组分组
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语言数组越界不报错,这里越界的话直接就是无解 还是去看递归的实现