配列 arr と差分が与えられた場合、arr 内の数値の順序を乱すことなく最長のサブシーケンスを抽出し、シーケンス内のすべての隣接する 2 つの要素間の差分が相違となるようにします。条件を満たす最長のサブシーケンスの長さを求めます
。
アイデア:
DP
差分差分は固定されるため、要素を抽出するたびにその前の要素も固定されます。
たとえば、現在の要素が arr[ i ] である場合、その前の要素は arr[ i ] - 差分でなければならないため、
arr[ i ] までのシーケンス長も固定されます。
arr[ i ] までの部分列の長さをカウントするだけで済みます。
これらの長さの最大値をメモしておきます。
dp 配列は、hashMap を使用して (arr[ i ]、arr[ i ] までのサブシーケンスの長さ)、
または配列を保存できます。
(1)ハッシュマップ
public int longestSubsequence(int[] arr, int difference) {
Map<Integer,Integer> dp = new HashMap<>();
int n = arr.length;
int res = 0;
for(int i = 0; i < n; i++) {
dp.put(arr[i], dp.getOrDefault(arr[i]-difference, 0)+1);
res = Math.max(res, dp.get(arr[i]));
}
return res;
}
(2) 配列は
要素に直接添字を付けるので高速です
記憶領域を節約するため、dp 配列の長さは arr の最大値 - 最小値 + 1 になります。
ただし、dp の添字は arr であることに注意してください。 [ i ] - 分、および arr の添字 i ではありません。
public int longestSubsequence(int[] arr, int difference) {
int min = Integer.MAX_VALUE;
int max = Integer.MIN_VALUE;
int res = 1;
for(int num : arr) {
min = Math.min(min, num);
max = Math.max(max, num);
}
int[] dp = new int[max-min+1];
for(int i = 0; i < arr.length; i++) {
int cur = arr[i] - min;
int pre = cur - difference;
if(pre >= 0 && pre < dp.length) {
dp[cur] = dp[pre] + 1;
if(dp[cur] > res) res = dp[cur];
} else {
dp[cur] = 1;
}
}
return res;
}