最も長く増加しているサブシーケンスのための6つのソリューション(gitbuhプロジェクト:AlgorithmPractice)

プロジェクト紹介

  • このプロジェクトは、主要な工場の一般的な筆記面接の質問を分解し、データ構造とアルゴリズムの基礎となる実装原理までソースをたどり、それらが何であるかを知っています。
  • 簡単な検索のための知識構造システムを確立し、志を同じくする友人をプロジェクトAlgorithmPracticeに参加するように歓迎します(問題とプルリクエストは歓迎されます)。

最も長く増加しているサブシーケンスは何ですか

  • 特定の数値シーケンスで、このサブシーケンスの要素の値が順次増加し、このサブシーケンスの長さが可能な限り長くなるように、サブシーケンスを見つけます。最も長く増加するサブシーケンスの要素は、元のシーケンスでは必ずしも連続していません。
  • この質問に対する6つの解決策を学習した後、面接担当者を見せてください。

6つのソリューション

テキストの始まり

1.暴力法

  • コードの実装LIS_Violence、テストケース:TestLIS_Violence
  • デザインのアイデア
    • 文字列のすべての可能な要素をトラバースし、これらの可能性が増加する法則に準拠しているかどうかを判断し、最も長い部分文字列の長さを数えます。
  • メインコード
//外循环是字符串的起始位置
for (int beginLocation = 0; beginLocation < sequence.length() - 1; beginLocation++) {
    
    
    //内部循环是暴力字符串的长度增长空间
    for (int subLength = 1; subLength < sequence.length() - beginLocation; subLength++) {
    
    
         sb = new StringBuffer();
         sb.append(sequence.charAt(beginLocation));
         dealString(sb, sequence, beginLocation, subLength);
    }
}
//生成字符串,其中beginLocation的字符是必须包含的
public void dealString(StringBuffer sb, String s, int beginPosition, int strdepth) {
    
    
     if (strdepth == 0 && judge(sb.toString())) {
    
    
      	  if (sb.length() > best_length) {
    
    
                best_length = sb.length();
          }
          return;
     }
     for (int i = beginPosition + 1; i < s.length(); i++) {
    
    
          sb.append(s.charAt(i));
          dealString(sb, s, i, strdepth - 1);
          sb.deleteCharAt(sb.length() - 1);
     }
}
    • 統計に使用される一時配列または一時リストは、次の操作が実行されるときにクリアされる必要があるたびに。
    • 走査文字列のすべてのコンポーネントは再帰によって行われます。再帰の前後の選択、特にStringBuffer.deleteCharAt()メソッドに注意する必要があります。内部のパラメーターは現在のループ値を使用できませんが、StringBuffer.length()-1を使用できます。

2.動的計画法

  • コードの実装LIS_Dynamic、テストケース:TestLIS_Dynamic
  • デザインのアイデア
    • 文字列の任意の点でのJの最大部分文字列の場合、それは、その前の部分文字列の最大数に1を足したものに等しくなります。
    • 状態遷移方程式:longest [i] =(longest [j] + 1)> longest [i]?(Longest [j] + 1):longest [i];
  • メインコード
for (int i = 0; i < length; i++) {
    
    
    for (int j = 0; j < i; j++) {
    
    
         if ((intArray[j] < intArray[i])) {
    
    
             longest[i] = (longest[j] + 1) > longest[i] ? (longest[j] + 1) : longest[i];
         }
    }
    if (longest[i] > best) {
    
    
         best = longest[i];
         point = i;
    }
}

3.分割統治[連続する部分文字列に限定、この質問は参照用のみ]

  • コードの実装LIS_Divide、テストケース:TestLIS_Divide
  • デザインのアイデア
    • 指定された文字列には、特定の最大長増加サブシーケンスが必要です。指定された文字列を左側と右側に分割すると、この最大増加サブシーケンスは、左側のサブストリング、右側のサブストリング、または水平のいずれかに存在します。左と右をクロスします(これはナンセンスではありません)。
    • 両側にまたがる部分文字列の場合、左に拡張して、それよりも小さい、最も長く増加する部分列を見つけます。同じことが右にも当てはまりますが、この問題を行う場合、サイズの判断しか行わないため、この方法で解決できるのは連続インクリメントと非連続サブストリングのインクリメントの問題は、動的プログラミングが必要になる場合があります。
  • メインコード
public int divide(int[] stringArr, int left, int right) {
    
    
	if (left < right) {
    
    
		int mid = (left + right) / 2;
		int leftValue = divide(stringArr, left, mid);
		int rightValue = divide(stringArr, mid + 1, right);
		int midValue = middleHandle(stringArr, left, right);
		return Math.max(Math.max(leftValue, rightValue), midValue);
	}
	return 0;
}
//向左扩展
while (leftPoint - 1 >= left && stringArr[leftPoint] > stringArr[leftPoint - 1]) {
    
    
    count++;
    leftPoint--;
}
//向右扩展
while (rightPoint + 1 <= right && stringArr[rightPoint] < stringArr[rightPoint + 1]) {
    
    
    count++;
    rightPoint++;
}
    • このソリューションは、最も長く増加するサブシーケンスを解決するために使用するのではなく、最も長く連続的に増加するサブシーケンスを計算するためにのみ使用する必要があります。

4.文字列比較メソッド

  • コードの実装LIS_Lcs、テストケース:TestLIS_Lcs
  • デザインのアイデア
    • 文字列を配列から外して並べ替えます
    • ソートされた配列は重複排除されます(増分が単調ではなく、重複データがないことを考慮して)
    • 重複排除された配列を文字列に変換し、最も長い共通のサブシーケンスを元の文字列と比較します(本質は依然として動的プログラミングのアイデアです)。
  • メインコード
//进行快速排序
QuickSortDuplexing q = new QuickSortDuplexing();
q.sortMethod(ints);
//因为是递增序列,所以要去重
HashMap hashMap = new HashMap();
for (int i = 0; i < c.length; i++) {
    
    
    hashMap.put(ints[i], 1);
}
String temp = hashMap.keySet().toString().replace(",", "").replace("[", "").replace("]", "").replace(" ", "");
//再进行最长子序列比较
LCS lcs = new LCS();
int length = lcs.count(temp, sequence).getCommondLength();
    • 重複排除はハッシュマップのキーを選択します
    • ハッシュマップを文字列に変換するために、多くの置き換えがあり、現時点ではこれ以上の方法は見つかりませんでした。

5.ブランチとバインドされたメソッド

  • コードの実装LIS_Branch、テストケース:TestLIS_Branch
  • デザインのアイデア
    • ブランチアンドバウンド方式は、暴力法を改善したものであり、いくつかの明らかな条件を取り除きます。
    • といった:
      • 現在のtemp値とトラバースする残りの距離の合計が最適値以下の場合、続行する必要はありません。
      • トラバースする残りの距離が現在の最適解よりも短いため、続行する必要はありません。
  • メインコード
//剩下的待遍历距离小于当前的最优解,就没有必要再继续下去了。
for (int i = 1; count_best <= length - i; i++) {
    
    
    list_temp = new ArrayList();
    list_temp.add(StringArray[i - 1]);
    count_temp = 1;
    count(i);
}
//当前temp的值加上剩下待遍历的距离,小于等于最优值的时候,就没有必要再继续下去了。
if ((length - 1) - depth + (count_temp + 1) <= count_best) {
    
    
    return;
}

if (count_temp > count_best || depth == length - 1) {
    
    
    //更新最优解,并继续下去
    if (count_temp > count_best) {
    
    
        list_best = new ArrayList<>(list_temp);
        count_best = count_temp;
    }
    //达到终点,停止递归
    if (depth == length - 1) {
    
    
        return;
    }

}
//分支递归
for (int i = depth; i < length; i++) {
    
    
    if (list_temp.get(count_temp - 1) < StringArray[i]) {
    
    
        count_temp++;
        list_temp.add(StringArray[i]);
        count(i + 1);
        list_temp.remove(list_temp.get(--count_temp));
    }
}
    • リストが割り当てられている場合、これによって参照が従うことはありません。list_best = new ArrayList <>(list_temp);

6.ポーカー法[ポーカー法の本質は分割統治の考え方です]

  • コードの実装LIS_PokerTestLIS_Poker
  • デザインのアイデア
    • トランプのプレイ方法によると、最初のカードは自己開放型です。
    • 2つ目は1つ目よりも小さいため、1つ目の上にあります
    • 2番目のスタックは最初のスタックよりも大きく、別のスタックが開かれます。
    • 3番目は2番目よりも小さいので、2番目の上にあります
    • 3番目のものは2番目のものより大きく、別のスタックが再生されます。
    • スタックの最終的な数は、必要なサブシーケンスの最も長く増加する数です。異なるスタックに配置され、厳密に増加している組み合わせを確実に見つけることができます。数学的な証明は省略されています。
  • メインコード
for (int i = 0; i < count; i++) {
    
    
	left = 0;
	right = piles;
	poker = intArray[i];
	while (left < right) {
    
    
		mid = (left + right) / 2;
		if (poker < top[mid]) {
    
    
			right = mid;// ? right = mid-1;
		} else if (poker > top[mid]) {
    
    
			left = mid + 1;
		} else {
    
    
			right = mid;
		}
	}
	if(left == piles){
    
    
		piles++;
	}
	top[left] = poker;
}

おすすめ

転載: blog.csdn.net/ljfirst/article/details/106596812