小题
题目一:
给定一整型数组,从中找到两个数以使得他们的加和等于给定的数。
其中,时间复杂度要求O(n)
函数原型:
(1)Python语言:
class Solution:
# @return a tuple, (index1, index2)
def twoSum(self, num, target):
#your code
(2)C语言:
int *twoSum(int numbers[], int n, int target) {
}
返回值:整型数组中两个数的下标index1,index2(其中,index1<index2)
测试用例:
Input: numbers={2, 7, 11, 15}, target=9
Output: index1=1, index2=2
Input: numbers={0,0,3,2,8,9,7,8,9,7}, target=0
Output: index1=1, index2=2
c语言版:
新学了一个叫map的东东,听说是个容器,用于hash对应。
#include <stdio.h> #include<map> using namespace std; int re[2]; int *twoSum(int numbers[], int n, int target) { map<int, int> m; int r, l = n; while (l--) { r = m[target - numbers[l]];//没有对应的值则为0 if (r != 0){ //有对应的值表示当前的数和r位置的数是结果 re[0] = l + 1; re[1] = r + 1; break; } m[numbers[l]] = l; } return re; } int main(){ int n=4; int numbers[]={2, 7, 11, 15}; int target=13; int *result; result=twoSum(numbers,n,target); printf("index1=%d,index2=%d\n",result[0],result[1]); return 0; }
python版(有问题):
# -*- coding: utf-8 -*- class Solution: # @return a tuple, (index1, index2) def twoSum(self, num, target): index = range(len(num)) #下标 d=dict(zip(num,index)) #原列表与下标对应起来,形成字典 find=0 print 'd=',d for n in num: # print 'n=',n # print 'target-n=',target-n if ((target-n) in d.keys())and(d[target-n]!=d[n]): index1=d[n]+1 index2=d[target-n]+1 print'' find=1 break if find==0: print"there is no results" else: return (index1,index2) if __name__=="__main__": num=[1,0,5,0,8] print num target=0 S=Solution() result=S.twoSum(num,target) print("index1=",result[0],"index2=",result[1])
原谅我放了一个有问题的代码,本来觉得用字典很是方便,不过它不允许存在键值相同的元素,如果遇到num=[2,3,3,3,5],target=6这种情况怎么办呢?
对了,刚开始还把列表初始化用成了{},还以为列表是无序的,错怪了它。
题目二:
给定一个字符串S,找到S中最长的回文字串。假设S的长度小于1000,并且只存在一个最长回文字串。
补充:回文字串就是字符串正序和逆序是完全相同。
要求:时间复杂度不超过O(n^2),有能力考虑O(nlogn)或者O(n)算法
函数原型:
返回值:最长回文字串的起始地址,并将其打印出来
C语言:char *longestPalindrome(char *s) {
}
Python语言:
class Solution:
# @return a string
def longestPalindrome(self, s):
测试用例:
Input: str = ‘eabcbadf’
Output: ‘abcba’
#include <stdio.h>
#include <cstring>
int p[2005];//对应以每个字符为中心的回文串的长度的一半,人家叫半径好吧
char str[2005];
int min(int a,int b){
if(a<b)
return a;
else
return b;
}
char *longestPalindrome(char *s) {
int len = strlen(s), k = 1, i, num;
str[0] = '$';
for (i = 0; i < len; ++i){
str[k++] = s[i];
str[k++] = '#';
}
str[k - 1] = '@';
//以上是加工原字符串,将每个字符用'#'隔开,以保证‘aa’这种也可以被处理
p[0] = 0;
int maxRight = 1, maxCenter = 1;
//maxCenter是已处理的字符串的最大回文串的中心位置,maxRight是该回文串的最右位置,记录最右位置的意义就在于每个字符只需要被计算一遍,不走回头路,才能将效率提高到O(n)
int re=0;//re的含义后面揭晓
for (i = 1; i < k; ++i){
if(maxRight > i)//如果现在的位置被包括在到目前为止最大的回文串,可以找到与它对称的那个点作为参考,还挺聪明的
p[i] = min(maxRight - i + 1, p[(maxCenter<<1) - i]);
else
p[i] = 1;
while(str[i - p[i]] == str[i + p[i]])//然后往两边扩展
++p[i];
if(i + p[i] - 1 > maxRight){//如果扩展的超过了原来的最大回文串的位置,就再往后面挪动
maxRight = i + p[i] - 1;
maxCenter = i;
}
if(p[i] > p[re])//以re为中心的回文串最长
re = i;
else if(p[i] == p[re] && str[i] != '#')
re = i;
}
k = 0;
num = p[re];//num是最大回文串的半径
re -= (num - 1);//re变身为最大回文串起始位置
num = (num << 1) - 1;//num变身为最大回文串结束位置
for(i = 0; i < num; ++i) {//这里真的是从0开始吗?!!!
if(str[re] != '#')
str[k++] = str[re];
++re;
}
str[k] = 0;//将最大回文串存放到str里,并以0结尾
return str;
}
int main() {
char originalStr[2005], *result;
gets(originalStr);
result = longestPalindrome(originalStr);
printf("%s\n", result);
return 0;
}
我可以说这个题已经远远超出了我的智力范围了吗,一个点一个点的给我讲都是打了二十多个哈欠才勉强有点懂了,更别说自己看代码了。
至于什么是动态规划,原来这个算法是Manacher算法,好吧,恕我无知。随便找个人家的帖子都比我说的清楚很多,先记录一个吧:
http://blog.csdn.net/pi9nc/article/details/9251455