面试题 17.08. 马戏团人塔
描述
有个马戏团正在设计叠罗汉的表演节目,一个人要站在另一人的肩膀上。出于实际和美观的考虑,在上面的人要比下面的人矮一点且轻一点。已知马戏团每个人的身高和体重,请编写代码计算叠罗汉最多能叠几个人。
思路
- 其实是寻找一个数组的最长升序排列,我们将身高,体重变成二维联合数组,按以一维(身高)元素升序排列,这样只要找到二维(体重)元素其最长的升序排列就行(需要注意,身高相同时,体重要降序排列,防止将同一身高加入)
- 假设dp是排列后的体重数组,res是目前最大长度
- 遍历体重数组,找出其元素在dp的位置(详见方法binarySearch())
- 如果找出的索引等于res,则res++,最后返回的res则是最多可以叠的人数
题解
class Solution {
public int bestSeqAtIndex(int[] height, int[] weight) {
int n = height.length;
int[][] per = new int[n][2];
for(int i = 0; i < n; i++){
per[i] = new int[]{height[i], weight[i]};
}
//排序,根据二维数组第一维升序排序,如果第一维相等,第二维度降序排列
Arrays.sort(per, (a, b) -> a[0] == b[0] ? b[1] - a[1] : a[0] - b[0]);
int[] dp = new int[n];
int res = 0;
for(int i = 0; i < n; i++){
//查找该数是否在dp中,并返回相关索引值(规则见该函数)
int idx = Arrays.binarySearch(dp, 0, res, per[i][1]);
if(idx < 0){
idx = -(idx + 1);
}
dp[idx] = per[i][1];
//相等说明叠上,长度加1
if(idx == res){
res++;
}
}
return res;
}
}
1046. 最后一块石头的重量
描述
有一堆石头,每块石头的重量都是正整数。
每一回合,从中选出两块 最重的 石头,然后将它们一起粉碎。假设石头的重量分别为 x 和 y,且 x <= y。那么粉碎的可能结果如下:
如果 x == y,那么两块石头都会被完全粉碎;
如果 x != y,那么重量为 x 的石头将会完全粉碎,而重量为 y 的石头新重量为 y-x。
最后,最多只会剩下一块石头。返回此石头的重量。如果没有石头剩下,就返回 0。
思路
- 升序排列
- 取最大两个数相减,如果为0,则跳过,不为0,则数组长度减1,将差值加入到数组最后
- 重新排列求值,直到n小于等于1
- 最后n为0返回0,否则返回stones[0]
题解
class Solution {
public int lastStoneWeight(int[] stones) {
int n = stones.length;
while(n > 1){
Arrays.sort(stones);
int tmp = stones[n - 1] - stones[n - 2];
if(tmp == 0){
n = n - 2;
continue;
}
n = n - 1;
stones[n - 1] = tmp;
}
return n == 0 ? 0 : stones[0];
}
}
拓展
最大堆 java真牛啊,库真多
class Solution {
public int lastStoneWeight(int[] stones) {
PriorityQueue<Integer> pq = new PriorityQueue<Integer>((a, b) -> b - a);
for (int stone : stones) {
pq.offer(stone);
}
while (pq.size() > 1) {
int a = pq.poll();
int b = pq.poll();
if (a > b) {
pq.offer(a - b);
}
}
return pq.isEmpty() ? 0 : pq.poll();
}
}