一道面试题的解答_骑士获得金币问题

这道题是今天晚上在c++交流群和一位水友给出的问题,有些同学试着解答了下;问题阐述如下:

题目文字略去,看图即可。

《一道面试题的解答_骑士获得金币问题》

其中@jevon 的解答如下:

《一道面试题的解答_骑士获得金币问题》

也没有帮他验证;但是基本思路就是:

遍历每一天,用一个 index 值来记录当天的索引,当出现次数 cout 达到索引值时,索引值++;

我于是帮他用java写一个就是这个意思;我的vs出问题了,所以用的java;

public class Demo33 {
	public static void main(String[] args) {
		for(int i=1;i<=20;i++){
			setMC(i);
		}
	}
	public static int setMC(int day){
		int sum = 1;
		int cout = 1;
		int index = 1;
		String s = "1";
		for(int i=1;i<day;i++){
			if(cout < index-1){
				cout++;
			}else{
				cout = 0;
				index++;
			}
			sum += index;
			
			if(i != day-1){
				s = s + "+" + index;
			}else{
				s = s + "+" +index + "=" + sum  ;
			}
		}
		System.out.println(s);
		return sum;
	}
}

但是经过我的思考,一道程序题不是为了考察编写程序而单一的出现,所以一定是有优化的方法

所以经过我的思考,发现索引值满足;索引值为a;

等差数列求和 a(a-1)/2 <= day < a(a+1)/2;所以可以计算出完整的a;同时得到剩下的p个(a+1)项

例如 1+2+2+3+3+3+4+4;这里面a = 3;p = 2;凑成完全的1+2^2+3^2+3^2;的索引正好是3;余下两个p (index) = a+1的残项;

而输入的结果 result = 1^2 + 2^2 + … a^2 + (a+1) * p = a(a+1)(2a+1)/6 + p(a+1);

所以编写程序如下:

import java.util.Scanner;

public class Demo {
	public static void main(String[] args) {
		int day = new Scanner(System.in).nextInt();
		int a = setCout_n(day);//a就是能凑成完整的1+2^2+3^2+...+a^2 + (a+1)*p;
		int p = day - (int)(a*(a+1)/2);
		int result = (a*(a+1)*(2*a+1)/6) + (a+1)*p;
		System.out.println(result);
	}
	
	public static int setCout_n(int day){
		int n = (int)(Math.sqrt(2*day + 0.5)+0.25);
		while(day < (int)((n*n - n)/2 + 0.5)){
			n++;
		} 
		return n-1;
	}
}

要是为了看到完整的验算过程;补充一个printRR函数,方便观看1-100完整的生成过程。

下面是验算的代码块,和上面的函数相同,只是加了一些控制台输出。

public class Demo {
	public static void main(String[] args) {
		for (int i=0;i<100;i++){
			demo(i);
		}
	}

	public static void demo(int day) {
		int a = setCout_n(day);//a就是能凑成完整的1+2^2+3^2+...+a^2 + (a+1)*p;
		System.out.println("输入天数" + day);
		int p = day - (int)(a*(a+1)/2);
		System.out.println("完全数a = "+ a +", 余下来的p项,p = "+p);
		int result = (a*(a+1)*(2*a+1)/6) + (a+1)*p;
		System.out.println(result);
		printRR(a, p);
	}
	
	public static int setCout_n(int day){
		int n = (int)(Math.sqrt(2*day + 0.5) + 0.25);
		while(day < (int)((n*n - n)/2 + 0.5)){
			n++;
		} 
		return n-1;
	}
	public static void printRR(int a,int p){
		String s ="[";
		int sum = 0;
		for(int i=1;i<=a;i++){
			s = s+ "(";
			for (int j=0;j<i;j++){
				if(j==0){
					s = s + i;sum+=i;
				}else{
					s = s + "+" + i;sum+=i;
				}
			}
			if(i==a){
				s = s+")";
				}else{
					s =s + ")+";}
		}
		if(p>0){
			s = s +"+(";
			for (int j = 0; j< p;j++){
				if(j==0){
					s = s + (a+1);
					sum+=(a+1);
				}else{
					s = s + "+" + (a+1);
					sum+=(a+1);
				}
			}
			s = s+")";
		}
		s = s + "] = "+ sum;
		System.out.println(s);
	}
}

结论:这个题要是用数学知识直接解答复杂度大大降低,忽略系统运算中sqrt的复杂度;我们可以得到我的方法时间复杂度大约是O(lg(n));而他的方法是O(n).

    原文作者:骑士周游问题
    原文地址: https://blog.csdn.net/actanble/article/details/52601639
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞