剑指offer 之 和为S的连续正数序列

本文介绍了一种寻找所有和为给定数值S的连续正数序列的方法。通过构造首个符合条件的序列并以此为基础,推导出所有可能的序列组合。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列? Good Luck!
输出描述:
输出所有和为S的连续正数序列。序列内按照从小到大的顺序,序列间按照开始数字从小到大的顺序。
分析:
我们可以用一种很巧妙的方式,首先因为这些序列中都有关系,也就是后面的那个序列都是由前一个序列推出来的,所以我们首先就要得到第一个序列,那么如何得到第一个序列呢?我们让从1开始加,直到加到某个数出现它的和大于或等于给定的sum。如果是等于,那么就将从1开始的这个序列直接保存到list中,但是还得再让它做一次遍历,减掉开头的那个值,然后再循环,直到出现大于给定的那个和为止。那么针对出现大于给定和的情况,我们发现,其实只要让给定的和去减掉现有的和,这个差值去 % 所有的求和数的个数 ,如果能够整除,那么相当于可以平均分配给前面的那几个数字,让那些数字都加上这个平均值即可,依次类推,其实剩下来的每一个序列都可以由这个第一个序列推出来的。
详细点:先找到第一个符合条件的序列,因为这一个序列必定是最长的,而且其他剩下的都可以通过它推出来,那么我们发现,接下来的这个序列必定是小于给定值的一个序列,然后我们再依次从第一个元素开始,将这个差值加上从头开始的元素的和,并且去除以剩下的元素的个数,如果能够整除,那么直接就将这个平均的数分别依次加到剩下的元素中去即可满足条件。
 public static ArrayList<ArrayList<Integer>> FindContinuousSequence(int sum)
 {
		  ArrayList<ArrayList<Integer>> list = new ArrayList<ArrayList<Integer>>();
            int s = 0;
            if(sum <= 2)    //为了防止出现单个数字的情况
               return list;
		  ArrayList<Integer> li = new ArrayList<Integer>();
		for(int i = 1; i <= (sum / 2) + 1; i++)   //只需要到这个给定和的一半加1即可
		{
			s += i;
			if(s < sum)
			   li.add(i);
			else if(s > sum)
			{
			    s -= i;
			    break;
			}
			else if(s == sum)
			{
			   li.add(i);
                           ArrayList<Integer> al = new ArrayList<Integer>();
                           for(int q = 0; q < li.size(); q++)
                              al.add(li.get(q));      //防止浅复制
			   list.add(al);
                           s -= li.get(0);
                           li.remove(0);
			}
		}
		if(!li.isEmpty() && li.size() > 2)
		{
			int[] temp = new int[li.size()];
			for(int j = 0; j < temp.length; j++)
				temp[j] = li.get(j);
			int tem = sum - s;
			int stmp = tem;
			for(int k = -1; k <= temp.length - 3; k++)
			{
                                if(k != -1)   //从0个开始
				   stmp += temp[k];   
				if(stmp % (temp.length - (k + 1)) == 0)
				{
					int avg = stmp / (temp.length - (k + 1));   //分配的平均值
					ArrayList<Integer> listtemp = new ArrayList<Integer>();
					for(int p = k + 1; p < temp.length; p++)
					{
					     listtemp.add(temp[p] + avg);
					}
					list.add(listtemp);
				}
			}
		}
		return list;
	}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值