DP35 最长等差数列 Longest Arithmetic Progression @geeksforgeeks

在一个有序数组里找等差数列,用3个指针,以中间指针为基准,移动前后指针。


Given a set of numbers, find theLength of theLongestArithmeticProgression (LLAP) in it.

Examples:

set[] = {1, 7, 10, 15, 27, 29}
output = 3
The longest arithmetic progression is {1, 15, 29}

set[] = {5, 10, 15, 20, 25, 30}
output = 6
The whole set is in AP

For simplicity, we have assumed that the given set is sorted. We can always add a pre-processing step to first sort the set and then apply the below algorithms.

Asimple solutionis to one by one consider every pair as first two elements of AP and check for the remaining elements in sorted set. To consider all pairs as first two elements, we need to run a O(n^2) nested loop. Inside the nested loops, we need a third loop which linearly looks for the more elements inArithmeticProgression (AP). This process takes O(n3) time.

We can solve this problem in O(n2) timeusing Dynamic Programming. To get idea of the DP solution, let us first discuss solution of following simpler problem.

Given a sorted set, find if there exist three elements in Arithmetic Progression or not
Please note that, the answer is true if there are 3 or more elements in AP, otherwise false.
To find the three elements, we first fix an element as middle element and search for other two (one smaller and one greater). We start from the second element and fix every element as middle element. For an element set[j] to be middle of AP, there must exist elements ‘set[i]‘ and ‘set[k]‘ such that set[i] + set[k] = 2*set[j] where 0 <= i < j and j < k <=n-1.
How to efficiently find i and k for a given j?We can find i and k in linear time using following simple algorithm.
1)Initialize i as j-1 and k as j+1
2)Do following while i >= 0 and j <= n-1
..........a)If set[i] + set[k] is equal to 2*set[j], then we are done.
……..b)If set[i] + set[k] > 2*set[j], then decrement i (do i–-).
……..c)Else if set[i] + set[k] < 2*set[j], then increment k (do k++).


How to extend the above solution for the original problem?
The above function returns a boolean value. The required output of original problem isLength of theLongestArithmeticProgression (LLAP) which is an integer value. If the given set has two or more elements, then the value of LLAP is at least 2 (Why?).
The idea is to create a 2D table L[n][n]. An entry L[i][j] in this table stores LLAP with set[i] and set[j] as first two elements of AP and j > i. The last column of the table is always 2 (Why - see the meaning of L[i][j]). Rest of the table is filled from bottom right to top left. To fill rest of the table, j (second element in AP) is first fixed. i and k are searched for a fixed j. If i and k are found such that i, j, k form an AP, then the value of L[i][j] is set as L[j][k] + 1. Note that the value of L[j][k] must have been filled before as the loop traverses from right to left columns.


package DP;

public class LongestArithmeticProgression {

	public static void main(String[] args) {
		int[] A = {1, 7, 10, 15, 27, 29};
		System.out.println(arithmeticThree(A, A.length));
		System.out.println(lengthOfLongestAP(A, A.length));
		int[] B = {1, 7, 10, 15, 27, 28};
		System.out.println(arithmeticThree(B, B.length));
		System.out.println(lengthOfLongestAP(B, B.length));
	}
	
	// 判断是否有等差数列的存在
	public static boolean arithmeticThree(int[] A, int n){
		for(int j=1; j<n-1; j++){		// j为等差数列中间那个数
			int i=j-1, k=j+1;
			while(i>=0 && k<=n-1){
				if(A[i]+A[k] == 2*A[j]){	// 找到
					return true;
				}else if(A[i]+A[k] > 2*A[j]){	// 过大
					i--;
				}else{	// 过小
					k++;
				}
			}
		}
		return false;
	}
	
	// Returns length of the longest AP subset in a given set
	// O(n^2) time, space
	public static int lengthOfLongestAP(int[] A, int n){
		if(n <= 2){
			return n;
		}
		
		// Create a table and initialize all values as 2. The value of
	    // L[i][j] stores LLAP with A[i] and A[j] as first two
	    // elements of AP. Only valid entries are the entries where j>i
		int[][] L = new int[n][n];		// L[i][j]: 以A[i]和A[j]为前两项的最长等差数列项数
		int llap = 2;		// 最长等差数列项数
		
		// Fill entries in last column as 2. There will always be
	    // two elements in AP with last number of set as second
	    // element in AP
		for(int i=0; i<n; i++){
			L[i][n-1] = 2;
		}
		
		// Consider every element as second element of AP
		for(int j=n-2; j>=1; j--){
			int i=j-1, k=j+1;		// Search for i and k for j
			while(i>=0 && k<=n-1){
				if(A[i]+A[k] < 2*A[j]){
					k++;
				}else if(A[i]+A[k] > 2*A[j]){	// Before changing i, set L[i][j] as 2
					L[i][j] = 2;		// 初始化,项数至少为2
					i--;
				}else{
				    // Found i and k for j, LLAP with i and j as first two
    	            // elements is equal to LLAP with j and k as first two
	                // elements plus 1. L[j][k] must have been filled
	                // before as we run the loop from right side
					L[i][j] = L[j][k] + 1;  // 因为包括了[i,j]和[j,k]两项,比原来的[j,k]多了一项
					
					// Update overall LLAP, if needed
					llap = Math.max(llap, L[i][j]);
					
					// Change i and k to fill more L[i][j] values for current j
					i--;
					k++;
				}
			}
			
			// If the loop was stopped due to k becoming more than
	        // n-1, set the remaining entities in column j as 2
			while(i >= 0){
				L[i][j] = 2;
				i--;
			}
		}
		
		return llap;
	}

}


http://www.geeksforgeeks.org/length-of-the-longest-arithmatic-progression-in-a-sorted-array/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值