算法之動態規劃最大遞增子序列問題(Java語言)

求解數組的最大子序列的個數問題

public static void main(String[] args) {

 	int[] arr = {1,5,2,7,4,9,10,11,8,14,13};
	System.out.println(maxLISCount1(arr));
	System.out.println(maxLISCount2(arr));
}

/**
  * 最長遞增子序列長度
  * int[] arr = {1,5,2,7,4,9,10,11,8,14,13};
  *
  * 1. 定義數組s[i] 是以arr[i]結尾的最大子序列的個數
  * 2. 分別計算s[i]
  * 3. 找出s[i]的最大值,並且返回
  */
 private static int maxLISCount1(int[] arr){
     //創建一個s數組,並且數值元素值爲1
     int[]s = new int[arr.length];
     for (int i = 0; i < s.length; i++) {
         s[i] = 1;
     }

     //計算s[i]的值。 s[i] = s[j]+1。 {存在一個最大的j使得j<i&& arr[j]<arr[i],且s[j]是最大值}
     for (int i = 0; i < arr.length; i++) {
         int item = arr[i];
         //判斷是有存在元素j,使得j<i&& arr[j]<arr[i]
         for(int j=i-1;j>=0;j--){
             if(arr[j]<item){
                 if(s[i]<s[j]+1){
                     s[i] = s[j]+1;
                 }
             }
         }
     }

     int count =0;
     for (int i = 0; i < s.length; i++) {
        if(count<s[i]){
            count = s[i];
        }

     }
     return count;
 }

 /**
  * 最長遞增子序列長度
  * int[] arr = {1,5,3,7,9,8};
  *
  * 創建一個棧,將元素壓棧,如果要壓棧的元素小於棧頂元素,則將該元素,替換棧中僅大於它的元素。否則直接壓棧。最後返回棧的長度。
  *
  */
 private static int maxLISCount2(int[] arr){
     //用隊列模仿棧的思想。
     List<Integer> list = new ArrayList<>();

     for (int i = 0; i < arr.length; i++) {
         if(list.isEmpty()){
             list.add(arr[i]);
         }else {
             if(list.get(list.size()-1)<arr[i]){
                 list.add(arr[i]);
             }else {
                 //定位並替換元素
                 for (int j = list.size()-1; j >= 0; j--) {
                     //替換並刪除
                     if(arr[i]<list.get(j)){
                         list.add(j,arr[i]);
                         list.remove(j+1);
                         break;
                     }

                 }
             }
         }
     }
     return list.size();
 }

求解數組的最大遞增子序列的問題

public static void main(String[] args) {

 	int[] arr = {1,5,2,7,4,9,10,11,8,14,13};
	System.out.println(maxLISListOne(arr2));
    List<List<Integer>> lists = maxLISListAll(arr2);
    for (List<Integer> i:
    lists){
        System.out.println(i);
    }
}


/**
 * 輸出一個最長遞增子序列
  * int[] arr = {1,5,3,7,9,8};
  *
  * 1. 定義數組s[i] 是以arr[i]結尾的最大子序列的個數
  * 2. 分別計算s[i]
  * 3. 找出s[i]的最大值,並且返回
  *
  */
 private static List<Integer> maxLISListOne(int[] arr){
     //創建一個s數組,並且數值元素值爲1
     int[]s = new int[arr.length];
     int[] pre = new int[arr.length];
     for (int i = 0; i < s.length; i++) {
         s[i] = 1;
     }

     for (int i = 0; i < pre.length; i++) {
         pre[i] = -1;
     }

     //計算s[i]的值。 s[i] = s[j]+1。 {存在一個最大的j使得j<i&& arr[j]<arr[i]}
     for (int i = 0; i < arr.length; i++) {
         int item = arr[i];
         //判斷是有存在元素j,使得j<i&& arr[j]<arr[i]
         for(int j=i-1;j>=0;j--){
             if(arr[j]<item){
                 if( s[i] < s[j]+1){
                     s[i] = s[j]+1;
                     pre[i] = j;
                 }
             }
         }
     }

     int endIndex =0;
     int count = 0;
     for (int i = 0; i < s.length; i++) {
        if(count<s[i]){
            count = s[i];
            endIndex = i;
        }
     }

     List<Integer> result = new ArrayList<>();

     while (endIndex>=0){
         //遍歷輸出結果
         result.add(arr[endIndex]);
         endIndex = pre[endIndex];
     }
     Collections.reverse(result);

     return result;

 }


 /**
  * 輸出所有最長遞增子序列,如果存在多個最長遞增子序列
  * int[] arr = {1,5,3,7,9,8};
  *
  * 1. 定義數組s[i] 是以arr[i]結尾的最大子序列的個數
  * 2. 分別計算s[i]
  * 3. 找出s[i]的最大值,並且返回
  *
  */
 private static List<List<Integer>> maxLISListAll(int[] arr){
     //創建一個s數組,並且數值元素值爲1
     int[]s = new int[arr.length];
     List<List<Integer>> pres = new ArrayList<>();
     for (int i = 0; i < s.length; i++) {
         s[i] = 1;
     }

     for (int i = 0; i < arr.length; i++) {
         pres.add(new ArrayList<>());
     }

     //計算s[i]的值。 s[i] = s[j]+1。 {存在一個最大的j使得j<i&& arr[j]<arr[i]}
     for (int i = 0; i < arr.length; i++) {
         int item = arr[i];
         //判斷是有存在元素j,使得j<i&& arr[j]<arr[i]
         //這裏一定要把所有的前驅都找出來
         for(int j=i-1;j>=0;j--){
             if(arr[j]<item){
                 if( s[i] < s[j]+1){
                     s[i] = s[j]+1;
                     pres.get(i).clear();
                     pres.get(i).add(j);
                 }else if(s[i]==s[j]+1){
                     pres.get(i).add(j);
                 }
             }
         }
     }

     List<Integer> endIndex = new ArrayList<>();
     int count = 0;
     for (int i = 0; i < s.length; i++) {
         if(count<s[i]){
             count = s[i];
             endIndex.clear();
             endIndex.add(i);
         }else if(count==s[i]){
             endIndex.add(i);
         }
     }

     //打印前驅數據
     System.out.println(pres);

     List<Integer> record = new ArrayList<>();
     List<List<Integer>> results = new ArrayList<>();
     compose(record,pres,endIndex,arr,results);
     return results;

 }

 /**
  * 根據記錄在數組pres中的前驅進行組合打印所有的可能
  * @param record
  * @param pres 
  * @param endIndex
  * @param arr
  * @param results
  */
 private static void compose(List<Integer> record, List<List<Integer>> pres, List<Integer> endIndex,int[]arr,List<List<Integer>>results) {
     if(endIndex.isEmpty()){
         List<Integer> a = new ArrayList<>(record);
         Collections.reverse(a);
         results.add(a);
         return ;
     }
     for (int index :
             endIndex) {
         //加入item arr[endIndex]
         record.add(arr[index]);
         compose(record,pres,pres.get(index),arr,results);
         record.remove(Integer.valueOf(arr[index]));
     }
 }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章