面试题17.08.马戏团人塔(排序+最长上升子序列)

118 阅读2分钟

「这是我参与2022首次更文挑战的第16天,活动详情查看:2022首次更文挑战」。

题目描述

image.png 这是leetcode上的一道面试题,题解思路如下

题解

这道题目题解分两步

1. 排序

按某一维度进行排序,这里用高度进行排序,同时需要注意,上升子序列不能身高和体重有任一相同的情况,所以在高度相同的情况下要按体重降序(按体重降序的话接下来只需要weight[i]>weight[i-1],就可以排除身高或体重相同的情况,因为如果weight[i]>weight[i-1]的话身高一定不同(身高相同与排序结果相斥)

2.最长上升子序列

  1. 维护一个单调栈(用数组实现)F[N]
  2. 原数组A[N],遍历A,如果F为空或栈顶元素小于A[i],那么直接入栈,否则通过二分查找找到第一个大于或等于A[i]的数然后将其替换为A[i]。这里简单理解一下,将前面元素用A[i]替换后后面的元素将更有机会加入到该单调栈中。
  3. 最后返回栈的大小就可以了。
class Solution {
    class Node{
        int height;
        int weight;
        Node(int height,int weight){
            this.height=height;
            this.weight=weight;
        }
    }
    //找到第一个大于或等于key的数
    public int upperBound(int[] arrays,int length,int key){
        int l=0;
        int r=length-1;
        while(l<=r){//最终会有l==r的情况,此时不管l右移还是r左移都会有arrays[l]>=key
            int mid=(l+r)/2;
            if(arrays[mid]<key)l=mid+1;
            else{
                //由于求得是第一个大于等于key的数,所以应该让区间往左。
                r=mid-1;
            }
        }
        return l;
    }
    public int bestSeqAtIndex(int[] height, int[] weight) {
        Node[] nodes=new Node[height.length];
        for (int i = 0; i < nodes.length; i++) {
            nodes[i]=new Node(height[i],weight[i]);
        }
        Arrays.sort(nodes, new Comparator<Node>() {
            @Override
            public int compare(Node o1, Node o2) {
                if(o1.height==o2.height)return o2.weight-o1.weight;
                return (o1.height-o2.height);
            }
        });
        int[] ans=new int[weight.length];
        int size=0;
        for (int i = 0; i < nodes.length; i++) {
            if(i==0)ans[size++]=nodes[i].weight;
            else{
                if(nodes[i].weight>ans[size-1]){
                    ans[size++]=nodes[i].weight;
                }else{
                    int pos=upperBound(ans,size,nodes[i].weight);
                    ans[pos]=nodes[i].weight;
                }
            }
        }
        return size;
    }
}

找到第一个大于等于key的数(二分)

//找到第一个大于或等于key的数
    public int upperBound(int[] arrays,int length,int key){
        int l=0;
        int r=length-1;
        while(l<=r){//最终会有l==r的情况,此时不管l右移还是r左移都会有arrays[l]>=key
            int mid=(l+r)/2;
            if(arrays[mid]<key)l=mid+1;
            else{
                //由于求得是第一个大于等于key的数,所以应该让区间往左。
                r=mid-1;
            }
        }
        return l;
    }