1. 程式人生 > >演算法題(二十七):和為S的連續正數序列

演算法題(二十七):和為S的連續正數序列

題目描述

小明很喜歡數學,有一天他在做數學作業時,要求計算出9~16的和,他馬上就寫出了正確答案是100。但是他並不滿足於此,他在想究竟有多少種連續的正數序列的和為100(至少包括兩個數)。沒多久,他就得到另一組連續正數和為100的序列:18,19,20,21,22。現在把問題交給你,你能不能也很快的找出所有和為S的連續正數序列?

分析

有兩種方法可解此題

1.雙指標法

規定一個視窗,視窗左右兩邊是兩個指標,根據視窗內值的和來確定視窗的位置和長度。若當前視窗內和小於S,右指標右移一位,若大於S則左指標右移一位,若等於S則將視窗內的值儲存到一個list中,並將左指標右移一位,重新開始,走到左指標超過右指標。

2.當n為奇數時,序列的中數正好是序列的均值即\frac{sum}{2},則sum\%n=0。當n為偶數時均值為中間兩個數的均值,這個平均值的小數部分為0.5,則(sum\%n)*2=n。由等差求和可知n<\sqrt{2S}。所以遍歷2~\sqrt{2S}之間n的值。中間值為\frac{sum}{n},起始值為medium-\frac{n-1}{2}

程式碼

import java.util.ArrayList;

public class ContinualSum {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		ArrayList<ArrayList<Integer>> res = fun2(50);
		for(ArrayList<Integer> list: res){
			for(int num: list){
				System.out.print(num+",");
			}
			System.out.println();
		}
	}

	public static ArrayList<ArrayList<Integer>> fun1(int sum){
		ArrayList<ArrayList<Integer>> res = new ArrayList<>();
		int plow=1;
		int phigh=2;
		while(plow<phigh){
			int cur = (phigh+plow)*(phigh-plow+1)/2;
			if(cur == sum){
				ArrayList<Integer> list = new ArrayList<>();
				for(int i=plow; i<=phigh; i++){
					list.add(i);
				}
				res.add(list);
				plow++;
			}else if(cur<sum){
				phigh++;
			}else{
				plow++;
			}
		}
		return res;
	}
	
	 public static ArrayList<ArrayList<Integer>> fun2(int sum){
		 ArrayList<ArrayList<Integer>> res = new ArrayList<>();
		 int n=(int) Math.sqrt(2*sum);
		 for(; n>=2; n--){
			 if((n & 1)==1 && sum % n==0 || (sum%n)*2==n){
				 ArrayList<Integer> list = new ArrayList<>();
				 //j是開始值
				 for(int i=0, j=(sum/n)-(n-1)/2; i<n; i++, j++){
					 list.add(j);
				 }
				 res.add(list);
			 }
		 }
		 return res;
	 }
}