[プログラマーコードインタビューガイド]最長増加するシーケンス(二点、DP)

タイトル

例:ARR = [2,1,5,3,6,4,8,9,7]、1,3,4,8,9最長増加するシーケンス

問題の解決策

STEP1:最長の連続したサブシーケンスの長さを取得します。

  • DPは、[]最長増加するシーケンスの長さは、ARRの[0..i]、ケースの端部にARR [I]に格納されています。
  • 余分さもなければ[]配列、初期化を終了する[0] = ARR [0]、及び0を終了します。それが有効領域の端部を有する、[0、R]数のみ有効面積理にかなっています。端部は、[i]は= NUM​​は、最小数NUMの終了時に、現在、長さI + 1のすべての増加シーケンスを横断表します。
  • プロセスがあっても前に[i]はARRの連続する配列の長さを増加させることで表現できる見つける左から右に番号のARRを[I]、活性領域は左端> = ARRを終了見つけるために[i]を、トラバース。
    • 見つかった場合、終了[J]と呼ばれる、[j]を終了する説明後者数が[I] ARRより大きい場合、それはDPである[i]を更新するために、J + 1、両端[j]を=
    • 見つからない場合は、[I] ARRより両端の数を示す[]アクティブ領域は小さいので、DP [I] =活性領域の+1長さ、アクティブ領域右境界R ++、両端[R]の更新です。
  • ENS []は非減少シーケンスであるので、二分探索を使用することが可能です
  • O(nlogn)の時間計算
    ステップ2:最長連続出力配列要素は
    、DPと表記、[]格納されているの最長の要素値のDP =長さを発見[I] ARRに対応する[i]は最後の要素です。次いで、格納されている値= -1 &&最長対応ARR [J] <ARR [I転送を受ける ] 位置、すなわち、最後から二番目の要素...

他の

  • 指定された要素よりも大きな最初の値を見つけるために、バイナリ検索:この質問は、古典的なバイナリ検索で使用されています。
  • 最終的には、それにL指し、最後の要素が指定された要素よりも大きい場合、得られるL L = R =中間でなければなりません。得られた逆++ L、L。
  • だから、右境界位置1に戻りますが見つからない場合は番号=とサイクリング条件は、Lは、返されます。

コード

public class Main {
    public static void main(String args[]) {
        int[] arr= {2,1,5,3,6,4,8,9,7};
        int[] incSec=getLongestIncSeq(arr);
        for(int num:incSec) {
            System.out.println(num);
        }
    }
    
    public static int[] getLongestIncSeq(int[] arr) {
        if(arr==null||arr.length==0) {
            return null;
        }
        
        int[] dp=getDp(arr);
        return getIncSeq(dp,arr);
    }
    
        //得到dp数组
    public static int[] getDp(int[] arr) {
        int[] dp=new int[arr.length];
        dp[0]=1;
        
        int[] ends=new int[arr.length];
        ends[0]=arr[0];
        int end=0;
        for(int i=0;i<arr.length;++i) {//遍历arr
            int pos=firstBigger(arr[i],ends,end);//遍历ends
            if(pos!=end+1) {//找到比arr[i]大的上升子序列结尾元素
                //更新dp和ends
                dp[i]=pos+1;//长度+1
                ends[pos]=Math.min(ends[pos], arr[i]);
            }
            else {//未找到比arr[i]大的上升子序列结尾元素
                //更新dp和ends
                dp[i]=end+1+1;//原长度+1
                ++end;
                ends[end]=arr[i];
            }
        }
        return dp;
    }
    
        //二分查找第一个比num小的元素
    public static int firstBigger(int num,int[] ends,int end) {//二分查找第一个比num小的元素
        int l=0;
        int r=end;
        while(l<=r) {//**
            int mid=(l+r)/2;//
            if(ends[mid]>=num) {
                r=mid-1;//
            }
            else {
                l=mid+1;//  
            }
        }
        return l;//**
    }
    
        //输出最长递增子序列
    public static int[] getIncSeq(int[] dp,int[] arr) {
        int len=Integer.MIN_VALUE;//代表新数组长度 ,并表示新数组索引
        int pos=-1;
        for(int i=0;i<dp.length;++i) {
            len=len>dp[i]?len:dp[i];
            pos=len>dp[i]?pos:i;//dp索引,arr索引
        }
        
        int[] incSeq=new int[len];
        incSeq[--len]=arr[pos];
        
        for(int j=pos;j>=0;--j) {
            if(dp[j]==len&&arr[j]<arr[pos]) {
                incSeq[--len]=arr[j];
                pos=j;
            }
        }
        return incSeq;
    }
}

おすすめ

転載: www.cnblogs.com/coding-gaga/p/11072343.html