数组
动态规划
题目描述
有一堆石头,用整数数组 stones
表示。其中 stones[i]
表示第 i
块石头的重量。
每一回合,从中选出任意两块石头 ,然后将它们一起粉碎。假设石头的重量分别为 x
和 y
,且 x <= y
。那么粉碎的可能结果如下:
如果 x == y
,那么两块石头都会被完全粉碎;
如果 x != y
,那么重量为 x
的石头将会完全粉碎,而重量为 y
的石头新重量为 y-x
。
最后,最多只会剩下一块 石头。返回此石头 最小的可能重量 。如果没有石头剩下,就返回 0
。
示例 1:
输入: stones = [2,7,4,1,8,1]
输出: 1
解释:
组合 2 和 4,得到 2,所以数组转化为 [2,7,1,8,1],
组合 7 和 8,得到 1,所以数组转化为 [2,1,1,1],
组合 2 和 1,得到 1,所以数组转化为 [1,1,1],
组合 1 和 1,得到 0,所以数组转化为 [1],这就是最优值。
示例 2:
输入: stones = [31,26,33,21,40]
输出: 5
提示:
1 <= stones.length <= 30
1 <= stones[i] <= 100
解法
方法一:动态规划
两个 石头的重量越接近,粉碎后的新重量就越小。同样的,两堆 石头的重量越接近,它们粉碎后的新重量也越小。
所以本题可以转换为,计算容量为 sum / 2
的背包最多能装多少重量的石头。
定义 dp[i][j]
表示从前 i 个石头中选出若干个,使得所选石头重量之和为不超过 j 的最大重量。
Python3 Java C++ Go Rust JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13 class Solution :
def lastStoneWeightII ( self , stones : List [ int ]) -> int :
s = sum ( stones )
m , n = len ( stones ), s >> 1
dp = [[ 0 ] * ( n + 1 ) for _ in range ( m + 1 )]
for i in range ( 1 , m + 1 ):
for j in range ( n + 1 ):
dp [ i ][ j ] = dp [ i - 1 ][ j ]
if stones [ i - 1 ] <= j :
dp [ i ][ j ] = max (
dp [ i ][ j ], dp [ i - 1 ][ j - stones [ i - 1 ]] + stones [ i - 1 ]
)
return s - 2 * dp [ - 1 ][ - 1 ]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 class Solution {
public int lastStoneWeightII ( int [] stones ) {
int s = 0 ;
for ( int v : stones ) {
s += v ;
}
int m = stones . length ;
int n = s >> 1 ;
int [][] dp = new int [ m + 1 ][ n + 1 ] ;
for ( int i = 1 ; i <= m ; ++ i ) {
for ( int j = 0 ; j <= n ; ++ j ) {
dp [ i ][ j ] = dp [ i - 1 ][ j ] ;
if ( stones [ i - 1 ] <= j ) {
dp [ i ][ j ] = Math . max ( dp [ i ][ j ] , dp [ i - 1 ][ j - stones [ i - 1 ]] + stones [ i - 1 ] );
}
}
}
return s - dp [ m ][ n ] * 2 ;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 class Solution {
public :
int lastStoneWeightII ( vector < int >& stones ) {
int s = accumulate ( stones . begin (), stones . end (), 0 );
int m = stones . size (), n = s >> 1 ;
vector < vector < int >> dp ( m + 1 , vector < int > ( n + 1 ));
for ( int i = 1 ; i <= m ; ++ i ) {
for ( int j = 0 ; j <= n ; ++ j ) {
dp [ i ][ j ] = dp [ i - 1 ][ j ];
if ( stones [ i - 1 ] <= j ) dp [ i ][ j ] = max ( dp [ i ][ j ], dp [ i - 1 ][ j - stones [ i - 1 ]] + stones [ i - 1 ]);
}
}
return s - dp [ m ][ n ] * 2 ;
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 func lastStoneWeightII ( stones [] int ) int {
s := 0
for _ , v := range stones {
s += v
}
m , n := len ( stones ), s >> 1
dp := make ([][] int , m + 1 )
for i := range dp {
dp [ i ] = make ([] int , n + 1 )
}
for i := 1 ; i <= m ; i ++ {
for j := 0 ; j <= n ; j ++ {
dp [ i ][ j ] = dp [ i - 1 ][ j ]
if stones [ i - 1 ] <= j {
dp [ i ][ j ] = max ( dp [ i ][ j ], dp [ i - 1 ][ j - stones [ i - 1 ]] + stones [ i - 1 ])
}
}
}
return s - dp [ m ][ n ] * 2
}
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 impl Solution {
#[allow(dead_code)]
pub fn last_stone_weight_ii ( stones : Vec < i32 > ) -> i32 {
let n = stones . len ();
let mut sum = 0 ;
for e in & stones {
sum += * e ;
}
let m = ( sum / 2 ) as usize ;
let mut dp : Vec < Vec < i32 >> = vec! [ vec! [ 0 ; m + 1 ]; n + 1 ];
// Begin the actual dp process
for i in 1 ..= n {
for j in 1 ..= m {
dp [ i ][ j ] = if stones [ i - 1 ] > ( j as i32 ) {
dp [ i - 1 ][ j ]
} else {
std :: cmp :: max (
dp [ i - 1 ][ j ],
dp [ i - 1 ][ j - ( stones [ i - 1 ] as usize )] + stones [ i - 1 ],
)
};
}
}
sum - 2 * dp [ n ][ m ]
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 /**
* @param {number[]} stones
* @return {number}
*/
var lastStoneWeightII = function ( stones ) {
let s = 0 ;
for ( let v of stones ) {
s += v ;
}
const n = s >> 1 ;
let dp = new Array ( n + 1 ). fill ( 0 );
for ( let v of stones ) {
for ( let j = n ; j >= v ; -- j ) {
dp [ j ] = Math . max ( dp [ j ], dp [ j - v ] + v );
}
}
return s - dp [ n ] * 2 ;
};
方法二
Python3 Java C++ Go
class Solution :
def lastStoneWeightII ( self , stones : List [ int ]) -> int :
s = sum ( stones )
m , n = len ( stones ), s >> 1
dp = [ 0 ] * ( n + 1 )
for v in stones :
for j in range ( n , v - 1 , - 1 ):
dp [ j ] = max ( dp [ j ], dp [ j - v ] + v )
return s - dp [ - 1 ] * 2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 class Solution {
public int lastStoneWeightII ( int [] stones ) {
int s = 0 ;
for ( int v : stones ) {
s += v ;
}
int m = stones . length ;
int n = s >> 1 ;
int [] dp = new int [ n + 1 ] ;
for ( int v : stones ) {
for ( int j = n ; j >= v ; -- j ) {
dp [ j ] = Math . max ( dp [ j ] , dp [ j - v ] + v );
}
}
return s - dp [ n ] * 2 ;
}
}
1
2
3
4
5
6
7
8
9
10
11
12 class Solution {
public :
int lastStoneWeightII ( vector < int >& stones ) {
int s = accumulate ( stones . begin (), stones . end (), 0 );
int n = s >> 1 ;
vector < int > dp ( n + 1 );
for ( int & v : stones )
for ( int j = n ; j >= v ; -- j )
dp [ j ] = max ( dp [ j ], dp [ j - v ] + v );
return s - dp [ n ] * 2 ;
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14 func lastStoneWeightII ( stones [] int ) int {
s := 0
for _ , v := range stones {
s += v
}
n := s >> 1
dp := make ([] int , n + 1 )
for _ , v := range stones {
for j := n ; j >= v ; j -- {
dp [ j ] = max ( dp [ j ], dp [ j - v ] + v )
}
}
return s - dp [ n ] * 2
}