编程之美重要题目整理

  1.数组分割

http://blog.csdn.net/yyme411/article/details/12156207

#include <stdio.h>
#include <math.h>
#define SUM_MAX 100
#define MLEN 20
int min(int a,int b)
{
	if (a<b)
		return a;
	else
		return b;
}
//F[i][j][k]表示前i个元素中选取j个使其和不超过但最逼近k的和
void fenge(int a[],int len,int sum)
{
	int i,j,k;
	int F[MLEN+1][MLEN/2+1][SUM_MAX/2+1]={0};
	int nLimit;
	int Path[MLEN+1][MLEN/2+1][SUM_MAX/2+1]={0};
	for (i=1;i<=len;i++)
	{
		nLimit=min(i,len/2);
       for (j=1;j<=nLimit;j++)
		{
			for (k=1;k<=sum/2;k++)
			{
				F[i][j][k]=F[i-1][j][k];//不选第i个元素
				if (k>=a[i-1])
				{
					if (F[i][j][k]<F[i-1][j-1][k-a[i-1]]+a[i-1])
					{
						F[i][j][k]=F[i-1][j-1][k-a[i-1]]+a[i-1];//选第i个元素
						Path[i][j][k]=1;
					}
				}
			}
		}
	}
	i=len;j=len/2;k=sum/2;//打印对应的数组,这里从F[2len][len][sum/2],k表示和
	while (i>=0&&j>=0&&k>=0)
	{
		if (1==Path[i][j][k])
		{
			printf("%d ",a[i-1]);
			--j;
			k=k-a[i-1]; //k表示和的形式,所以每次k要减去打印过的数
		}
		--i;
	}
	printf("\n");
}
int main()
{
	int a[]={1,5,7,8,9,6,3,11,20,17};
	int len=sizeof(a)/sizeof(a[0]); //数组长度
	int sum=0;
	int i;
	for (i=0;i<sizeof(a)/sizeof(a[0]);i++)
		sum+=a[i];
	fenge(a,len,sum);
	system("pause");
	return 0;
}

2.寻找发帖水王,即寻找数组中出现次数大于长度的一半的数。

http://www.cnblogs.com/sooner/archive/2013/04/02/2996589.html

3.字数组的最大乘积。 http://liuyangxdgs.blog.163.com/blog/static/2913776320111094252710/

4.连续子数组最大和 http://www.ahathinking.com/archives/120.html

下面说一下由DP而导出的另一种O(N)的实现方式,该方法直观明了,个人比较喜欢,所以后续问题的求解也是基于这种实现方式来的。

仔细看上面DP方案的代码,End[i] = max{arr[i],End[i-1]+arr[i]},如果End[i-1]<0,那么End[i]=arr[i],什么意思?End[i]表示以i元素为结尾的子数组和,如果某一位置使得它小于0了,那么就自当前的arr[i]从新开始,且End[i]最初是从arr[0]开始累加的,所以这可以启示我们:我们只需从头遍历数组元素,并累加求和,如果和小于0了就自当前元素从新开始,否则就一直累加,取其中的最大值便求得解。

5.数组循环移动位置 http://blog.csdn.net/laizemu/article/details/4046791

假设原数组序列为abcd1234,要求变换成的数组序列为1234abcd,即循环右了4。比较之后,不难看出,其中有两段的顺序是不变的:1234和abcd,可把这两段看成两个整体。右K的过程就是把数组的两部分交换一下。变换的过程通过以下步骤完成:

1.   逆序排列abcdabcd1234 → dcba1234;

2.   逆序排列1234:dcba1234 → dcba4321;

3.   全部逆序:dcba4321 → 1234abcd

6.字符串移位包含问题 http://blog.csdn.net/zzran/article/details/8465211

就是利用空间复杂度换取时间复杂度的方法:对于每次的移动,我们观察每次移除的字符,分别是A,A,B,C,D,如果把每次移除的字符放在原始字符串的后面,就会有如下的结果:AABCDA, AABCDAA, AABCDAAB, AABCDAABC, AABCDAABCD,所有移位之后的最后一个字符串,AABCDAABCD,看看有什么特点,它居然包含我们要找的字符串CDAA,可能有人认为这是一种巧合,那再看一个不成立的例子:ABCD, CDBA, ABCD移位并添加后的字符串是ABCDABCD, 可以看到ABCDABCD中有CDAB,但是没有CDBA,故这个算法还是正确的。但是要浪费一点空间。给出核心代码:

[cpp] 
view plain
copy

  1. int is_contain2(char *p_str, char *s_str) {  
  2.     int len_p = strlen(p_str);  
  3.     char *temp = (char*)malloc(2 * len_p + 1);  
  4.     strcpy(temp, p_str);  
  5.     strcpy(temp + len_p, p_str);  
  6.     if(strstr(temp, s_str)) {  
  7.         return 1;  
  8.     } else {  
  9.         return 0;  
  10.     }  
  11. }  

7,队列中取最大值问题

http://blog.sina.com.cn/s/blog_6421561201012vq1.html

8.

 快速寻找满足条件的两个数

http://www.cnblogs.com/bingwenst/archive/2012/05/22/2513151.html

首先对数组进行排序,时间复杂度为(N*log2N)。 

然后令i = 0,j = n-1,看arr[i] + arr[j] 是否等于Sum,如果是,则结束。如果小于

Sum,则i = i + 1;如果大于大于Sum,则 j = j – 1。这样只需要在排好序的数组上遍

历一次,就可以得到最后的结果,时间复杂度为O(N)。两步加起来总的时间复杂

度O(N*log2N)

    原文作者:代码小卒
    原文地址: https://blog.csdn.net/seuliujiaguo/article/details/39610301
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞