剑指Offer面试题41:求和为s的两个数字;求和为s的连续正数序列 Java实现

题目一:输入一个递增排序的数组和一个数字s,在数组中找两个数,使得他们的和刚好是s.如果有多对数字的和等于s,则输出任意一对即可。例如,输入数组{1,2,4,7,11,15}和数字15,则输出4和11(4+11=15)。
算法分析:
首先,我们会想到在数组中固定一个数字,再一次判断数组中其余n-1个数字与它的和是不是等于S。不过这个方法的时间复杂度为O(n^2),会不会有更快的方法?
接着我们提出时间更快的算法,我们现在数组中选择两个数字,如果它们的和等于输入的S,我们就找到了要找的两个数字。如果小于S呢?我们希望两个数字的和再大一点。由于数组已经排序好了,我们可以考虑选择较小的数字后面的数字,因为排在后面的数字要大一些,那么两个数字的和也要大一些,就有可能等于输入的数字S了。同样,当两个数字的和大于输入的数字的时候,我么可以选择较大数字前面的数字,因为排在数组前面的数字要小一些。
我们以数组{1,2,4,7,11,15}及期待的和为15为例详细分析一下这个过程。首先定义两个指针,第一个指针指向数组的第一个数字1,第二个指针指向数组的最后一个数字15.这两个数字的和为16大于15,因此我们把第二个指针向前移动一个数字,让它指向11.这个时候两个数字1与11的和为12,小于15,接下来我们把第一个指针向后移动一个数字指向2.此时两个数字2与11的和为13,还是小于15.我们再一次向后移动第一个指针,让它指向数字4.数字4与11的和是15,正是我们期盼的结果。


题目二:输入一个正数s,打印出所有和为s的连续正数序列(至少含有两个数)。例如,输入15,由于1+2+3+4+5=4+5+6=7+8=15,所以打印出三个连续序列:1,2,3,4,5;4,5,6;7,8.
算法分析:
有了前面的经验,我们也考虑用两个树small和big分别表示序列的最小值和最大值。首先把small初始化为1,big初始化为2.如果从small到big的序列的和大于s,我们可以从序列中去掉较小的值,也就是增大small的值。如果从small到big的序列的和小于s,我们可以增大big,让这个序列包含更多的数字。因为这个序列至少要有两个数字,我们一直增加small 到(1+s)/2为止。
以求和为9 的所有连续序列为例,我们先把small 初始化为1, big 初始化为2。此时介于small 和big 之间的序列是{1,2},序列的和为3,小于9,所以我们下一步要让序列包含更多的数字。我们把big 增加1 变成3,此时序列为{ I, 2,坷。由于序列的和是6,仍然小于9,我们接下来再增加big 变成4,介于small 和big 之间的序列也随之变成{ l, 2, 3, 4}。由于列的和10 大于9,我们要删去去序列中的一些数字, 于是我们增加small 变成2,此时得到的序列是{2, 3, 4}, 序列的和E好是9。我们找到了第一个和为9 的连续序列,把它打印出来。接下来我们再增加big,重复前面的过程,可以找到第二个和为9 的连续序列{4,5}。


题目1源程序:


/**************************************************************      
* Copyright (c) 2016, 
* All rights reserved.                   
* 版 本 号:v1.0                   
* 题目描述:求和为s的两个数字
*		        输入一个递增排序的数组和一个数字s,在数组中找两个数,使得他们的和刚好是s.
*			如果有多对数字的和等于s,则输出任意一对即可。例如,输入数组{1,2,4,7,11,15}和数字15,则输出4和11(4+11=15)
* 输入描述:请输入一个升序数组(以空格隔开):
*			1 2 3 5 6 7 8 9
*			请输入要查找的数字K:
*			8
* 程序输出:和为8的两个数是:1和7
* 问题分析: 无
* 算法描述:	接着我们提出时间更快的算法,我们现在数组中选择两个数字,如果它们的和等于输入的S,我们就找到了要找的两个数字。
* 			如果小于S呢?我们希望两个数字的和再大一点。由于数组已经排序好了,我们可以考虑选择较小的数字后面的数字,
* 			因为排在后面的数字要大一些,那么两个数字的和也要大一些,就有可能等于输入的数字S了。同样,
* 			当两个数字的和大于输入的数字的时候,我么可以选择较大数字前面的数字,因为排在数组前面的数字要小一些。
* 完成日期:2016-09-25
***************************************************************/
package org.marsguo.offerproject41;

import java.util.Scanner;

class FindSumNumberClass{
	public String FindFunction(int[] numarray,int k){
		if(numarray == null)
			return null;
		
		int i = 0;
		int j = numarray.length-1;
		int sum = 0;
		
		while(sum != k){
			sum = numarray[i] + numarray[j];
			if(sum > k){
				j--;
			}
			if(sum < k){
				i++;
			}
		}
		return numarray[i] + "和" + numarray[j];
	}
}
public class FindNumberWithSum {
	public static void main(String[] args){
		Scanner scanner = new Scanner(System.in);
		System.out.println("请输入一个升序数组(以空格隔开):");
		String str = scanner.nextLine();
		System.out.println("请输入要查找的数字K:");
		int k = scanner.nextInt();
		scanner.close();
		
		String[] temp = str.split(" ");
		int[] numarray = new int[temp.length];
		for(int i = 0; i < temp.length; i++){
			numarray[i] = Integer.parseInt(temp[i]);
		}
		
		FindSumNumberClass findclass = new FindSumNumberClass();
		System.out.print("和为" + k + "的两个数是:");
		System.out.println(findclass.FindFunction(numarray, k));
	}
}



题目二源程序:


/**************************************************************      
* Copyright (c) 2016, 
* All rights reserved.                   
* 版 本 号:v1.0                   
* 题目描述:求和为s的连续正数序列
*		        输入一个正数s,打印出所有和为s的连续正数序列(至少含有两个数)。例如,输入15,由于1+2+3+4+5=4+5+6=7+8=15,
*			所以打印出三个连续序列:1,2,3,4,5;4,5,6;7,8.
* 输入描述:请输入要求和的数字k:15
* 程序输出:和为15连续序列有:
*			1,2,3,4,5,
*			4,5,6,
*			7,8,
* 问题分析: 无
* 算法描述:	我们也考虑用两个树small和big分别表示序列的最小值和最大值。首先把small初始化为1,big初始化为2.
* 			如果从small到big的序列的和大于s,我们可以从序列中去掉较小的值,也就是增大small的值。
* 			如果从small到big的序列的和小于s,我们可以增大big,让这个序列包含更多的数字。
* 			因为这个序列至少要有两个数字,我们一直增加small 到(1+s)/2为止。
* 完成日期:2016-09-25
***************************************************************/

package org.marsguo.offerproject41;

import java.util.Scanner;

class FindSequenceClass{
	public void findSequenceFunction(int k){
		if(k <= 0)
			return;
		
		int small = 1;
		int big = 2;
		int end =( k + 1)/2;			//用于结束循环,当small接近K的一半时则不用再继续向后找了
		int sum = 0;					//初始和值设为0
		
		System.out.println("和为" + k +"连续序列有:");
		/*
		找出所有满足条件的序列,直到small到大k值的一半
		*/
		while(small <= end){
			sum = 0;
			for(int j = big; j >= small; j--)		//求big到small中间的所有序列和
				sum = sum + j;
			
			if(sum == k){
				for(int j = small; j <= big; j++)		//找到满足条件的和值后,输出该序列
					System.out.print(j + ",");
				System.out.println();
				big++;						//big++,继续向后寻找
			}
			else if(sum > k){
				/*如果sum大于要找的K,则将small向后移动,减小sum的值*/
				small++;
			}
			else if(sum < k){
				/*如果sum小于要找的K,则将big向后移动,增大sum的值*/
				big++;
			}
		}
	}
}

public class FindContinuousSequence {
	public static void main(String[] args){
		Scanner scanner = new Scanner(System.in);
		
		System.out.println("请输入要求和的数字k:");
		int k = scanner.nextInt();
		scanner.close();
		
		FindSequenceClass findsequence = new FindSequenceClass();
		findsequence.findSequenceFunction(k);
	}
}

程序运行结果:

剑指Offer面试题41:求和为s的两个数字;求和为s的连续正数序列 Java实现_第1张图片

剑指Offer面试题41:求和为s的两个数字;求和为s的连续正数序列 Java实现_第2张图片

你可能感兴趣的:(面试题,算法,剑指Offer)