每天一道算法题,菜鸟也能成高手!哈哈(2011年10月篇)

1、题目:输入一个正数n,输出所有和为n 连续正数序列。
例如输入15,由于1+2+3+4+5=4+5+6=7+8=15,所以输出3 个连续序列1-5、4-6 和7-8。

思路:

(思路是付老师提的,我之前都没想到,付老师雄起)

对输入的数num除以i,在得到的结果a附近找i个数,判断下和是否等于num就可以了。

public class continum {
static void find(int num){
	int a,sum,j;
	for (int i=2;i<num/2;i++)
	{
		a=num/i;
		int k;
		for(k=0;k<i;k++)
		{
			sum=i*(a-i+1)+k*i+i*(i-1)/2;
			if(sum==num&&(a-i+1)>0)
			{
				System.out.print(sum+"=");
				for(j=k;j<i+k;j++)
				{
					int m=a-i+j+1;
					if(m>0)
					{
						System.out.print(m+"+");
					}
					else break;
				}
			}
		}
		System.out.println();
	}
}
	public static void main(String[] args){
		find(25);//找25
	}
 }
输出还没有完善,逻辑是对的


 2、编程实现两个正整数的除法,当然不能用除法操作符。

// return x/y.
int div(const int x, const int y) {
....
}

思路:本题主要是因为两个整数相除,因此只考虑整数部分,不考虑小数。于是从1开始试,直到找出i与y相乘后的积与x的差在0~1之间即可。

public class div {
	static void div(int x,int y)
	{
		int i;
		for (i=1;i<=x;)
		{
			if (x-i*y>0 && x-i*y<y)
			{
				System.out.print(x+"/"+y+"="+i);
				break;
			}
			else i++;
		}
	}
	public static void main(String[]args)
	{
		div(12,8);
	}

}


 3、写程序找出二叉树的深度。

一个树的深度等于max(左子树深度,右子树深度)+1。可以使用递归实现。

假设节点为定义为
struct Node {
Node* left;
Node* right;
};

int GetDepth(Node* root) {
if (NULL == root) {
    return 0;
}
int left_depth = GetDepth(root->left);
int right_depth = GetDepth(root->right);
return left_depth > right_depth ? left_depth + 1 : right_depth + 1;
}


4 、(峰哥给的acm题)

Problem Description
A checksum is an algorithm that scans a packet of data and returns a single number. The idea is that if the packet is changed, the checksum will also change, so checksums are often used for detecting transmission errors, validating document contents, and in many other situations where it is necessary to detect undesirable changes in data.

For this problem, you will implement a checksum algorithm called Quicksum. A Quicksum packet allows only uppercase letters and spaces. It always begins and ends with an uppercase letter. Otherwise, spaces and letters can occur in any combination, including consecutive spaces.

A Quicksum is the sum of the products of each character's position in the packet times the character's value. A space has a value of zero, while letters have a value equal to their position in the alphabet. So, A=1, B=2, etc., through Z=26. Here are example Quicksum calculations for the packets "ACM" and "MID CENTRAL":

ACM: 1*1 + 2*3 + 3*13 = 46MID CENTRAL: 1*13 + 2*9 + 3*4 + 4*0 + 5*3 + 6*5 + 7*14 + 8*20 + 9*18 + 10*1 + 11*12 = 650

 
 
Input
The input consists of one or more packets followed by a line containing only # that signals the end of the input. Each packet is on a line by itself, does not begin or end with a space, and contains from 1 to 255 characters.
 
 
Output
For each packet, output its Quicksum on a separate line in the output.


 
 
Sample Input
ACM
MID CENTRAL
REGIONAL PROGRAMMING CONTEST
ACN
A C M
ABC
BBC
#
 
Sample Output
46
650
4690
49
75
14
15

 

在本题中,我发现用cin输入的时候是不能把回车作为一个元素存储到数组里面的,但是scanf可以。资料才知道:cin的输入忽略空格和回车。scanf("%c",&i)等价于i = getchar(),换行符和回车都会被读入。

我的做法比较蠢一点,把输入进来的字母都转换成对应的数字存储到整型数组s中。然后再计算和。我将数组初始化为-2,回车用-1表示。

#include <iostream> 
#include <math.h>
#include <string>
#include <stdio.h>
using namespace std;

void main()
{
	int s[255];//={-2};
	for(int m=0;m<255;m++){s[m]=-2;}//初始化数组
	int i=0;
	char ch;
	//cin>>ch;
	scanf("%c",&ch);
	while(ch != '#')
	{
		if(ch==' ')
		{
			s[i]=0;//空格存储为0
		}
		else if(int(ch)=='\n')
		{
			s[i]=-1;//回车存储为-1
		}
		else if(ch>='A' && ch<='Z')
		{
			s[i]=ch-'A'+1;//字母存储为对应的数字
		}
		else
		{
			break;
			cout<<"Wrong num"<<endl;
		}
		i++;
		scanf("%c",&ch);
	//	cin>>ch;
	}
	int j=0;
//	for(m=0;m<20;m++){cout<<s[m]<<endl;}
	while(s[j]!=-2)
	{
		int k=1;
		int sum=0;
		while(s[j]!=-1 && s[j]!=-2)
		{
			sum=sum+s[j]*k;
			k++;
			j++;
		}
		j++;
		cout<<"sum="<<sum<<endl;
	}

}


 5、输入为一个很长的字符串,字符之间是分段连续的(如bcdefbcdabbc),求里面最长的连续子序列,没有返回NULL,有则返回首地址及长度。(传说中腾讯面试题)

更宽泛一点:可以求最长的递增子序列

解题:我将字符存入字符数组,然后遍历数组,将连续的字符起止位置存入另外一个整型数组。最后输出的时候直接从整型数组中读取起止位置并比较起止位置之间的距离。输出距离最大的那个段。

#include <stdio.h>
void main()
{
	char s[255];
	int count[255];
	for(int m=0;m<255;m++){count[m]=-1;}
	char ch;
	int i=0,j=0;
	scanf("%c",&ch);
	if(ch!='#')
	{
		s[i]=ch;
		count[j]=i;
		scanf("%c",&ch);
		while(ch!='#')
		{
			if(ch>=s[i])
			{
				i++;
				s[i]=ch;
				scanf("%c",&ch);
			}
			else
			{
				j++;
				count[j]=i;
				i++;
				s[i]=ch;
				j++;
				count[j]=i;
				scanf("%c",&ch);
			}
		}
		count[j+1]=i;
	}
	else {printf("Wrong!");}
//for(m=0;m<10;m++){printf("%d\t",count[m]);}
	int k=0,max=0,a=0;
	j=0;
	while(count[j]!=-1)
	{
		a=count[j+1]-count[j];
		if(a>max)
		{
			max=a;k=j;//printf("k=%d,max=%d",k,max);
		}
		j=j+2;
	}
//	printf("k=%d,max=%d",k,max);
	printf("连续的串为:");
	for(j=count[k];j<=max+count[k];j++)
	{
		printf("%c\n",s[j]);
	}
}


 

6、判断一个自然数是否是某个数的平方。当然不能使用开方运算。

分析:

假设待判断的数字是 N。

方法1:
遍历从1到N的数字,求取平方并和N进行比较。
如果平方小于N,则继续遍历;如果等于N,则成功退出; 如果大于N,则失败退出。
复杂度为O(n^0.5)。

方法2:
使用二分查找法,对1到N之间的数字进行判断。
复杂度为O(log n)。

方法3:
由于
(n+1)^2
=n^2 + 2n + 1,
= ...
= 1 + (2*1 + 1) + (2*2 + 1) + ... + (2*n + 1)
注意到这些项构成了等差数列(每项之间相差2)。
所以我们可以比较 N-1, N - 1 - 3, N - 1 - 3 - 5 ... 和0的关系。
如果大于0,则继续减;如果等于0,则成功退出;如果小于 0, 则失败退出。
复杂度为O(n^0.5)。 不过方法3中利用加减法替换掉了方法1中的乘法, 所以速度会更快些。

 第三种解法比较好,我用代码实现了一下:

public class dermin_seq {
		static void dermin_seq(int N)
		{
			int i,count=N;
			int j=1;
			for(i=1;;)
			{
				count=count-i;
				if(count==0)
				{
					System.out.println(N+"="+j+"*"+j);break;
				}
				else if(count > 0)
				{
					i=i+2;j=j+1;
				}
				else
				{
					System.out.println(N+"不是自然数的平方");break;
				}
			}
		}
		public static void main(String[]args)
		{
			dermin_seq(25);
			dermin_seq(36);
			dermin_seq(33);
		}
}

7、【网易2012校招】编程题。编写代码把16进制表示的串转换为3进制表示的串。例如x=”5”,则返回:”12”;又例如:x=”F”,则返回”120”。

解:
我先将16进制转换为10进制,然后把10进制转换为3进制。

public class sixteentothree {
	/*10进制转为3进制*/
	public static void TentoThree(int N){
		int j=0,R,m,i=N;
		int[] A={-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
		while(i>0){
				A[j]=i%3;//取余数
				j++;
				i=i/3;//取商
			}
		for(m=A.length-1;m>=0;m--){if(A[m]>=0)System.out.print(A[m]);}
		System.out.println();
	}
	/*16进制转为10进制*/
	public static int SixteenToTen(char[] S){
		int M,i,j=0;
		int SUM=0;
		for(i=S.length-1;i>=0;i--){
			if(S[i]>='A' && S[i]<='F')
			{
				M=S[i]-55;
				//System.out.println(M);
				SUM=(int) (SUM+M*Math.pow(16,j));//pow(x,y):x的y次方
				//System.out.println(SUM);
				j++;
			}
			else if(S[i]>='0' && S[i]<='9')
			{
				M=S[i]-48;
				//System.out.println(M);
				SUM=(int) (SUM+M*Math.pow(16,j));
				//System.out.println(SUM);
				j++;
			}
			else {
				return -1;
			}
			}
		//System.out.println(SUM);
		return SUM;
		}
	public static void main(String[] args){
		//TentoThree(27);
		char[] S={'F','1','A','F'};
		//System.out.println(SixteenToThree(S));
		//TentoThree(431);
		TentoThree(SixteenToTen(S));
	}

}



8、【有道2012校招】
给定数列a0,a1,……,an,求和最接近0的连续子序列,如果有多个,输出所有子序列,每个一行。比如数列-1,3,1,-2,4,1时,和最接近0的连续子序列有两个,都是1,分别是1,-2和-1,3,1,-2,还有单独的-1和1.输入输出的格式均为每行一个数列,数间用空格分隔。
有多个子序列时,先输出开始位置更前的。若开始位置相同,输出结束位置更前的。
输入示例:
-1 3 1 -2 4 1
输出示例:
-1
-1 3 1 -2
1
1 -2

解:
看到这题就想到最大子序列的问题。之前有接触过,大概知道怎么做。今儿看了这题,想用二维数组解决一下试试。应该可以。将所有和的值存到二维数组中,二维数组的下标就是最小绝对值和的起止位置。哦,对了。题目说最靠近0的,其实就是和的绝对值最小的。

例如:


#include<stdio.h>
#include<math.h>
const int N=6;
void main()
{
	int B[N]={-1,3,1,-2,4,1};
	int a[N][N];
	int i,j,k;
	for(k=0;k<N;k++){a[k][k]=B[k];}//斜对角赋值
	for(i=0;i<N;i++)
	{
		for(j=i+1;j<N;j++)
		{
			a[i][j]=a[i][j-1]+B[j];
		}
	}
	int min=abs(a[0][0]);
	for(i=0;i<N;i++)//找最小值
	{
		for(j=i;j<N;j++)
		{
			if(abs(a[i][j])<min)
			{
				min=abs(a[i][j]);
			}
		}
	}
	for(i=0;i<N;i++)//输出
	{
		for(j=i;j<N;j++)
		{
			if(abs(a[i][j])==min)//扫描数组,找出与最小值相等的元素
			{
				for(k=i;k<=j;k++)
				{
					printf("%d ",B[k]);
				}
				printf("\n");
			}
			
		}
	}
}


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值