算法总结
腾讯面经中遇到的算法题:
http://blog.csdn.net/onever_say_love/article/details/51223886
1. 爬n阶楼梯,每次只能爬1步或者2步,求总的走法
2. 汉罗塔
3. 50亿qq排序
4. 海量数据下,如何做随机抽样
5. 蓄水池抽样
6. 海量文本下,字符串匹配,如何利用索引加快查找?(这题真不会,后来查了一下,可能跟lucene有关)
1. 两个字符串的最大公共子序列——构造回文O(MN)
题目:给定一个字符串s,你可以从中删除一些字符,使得剩下的串是一个回文串。如何删除才能使得回文串最长呢?输出需要删除的字符个数。
思路:这道题也就是求原字符串和其反转的最大公共子序列(不是字串,因为可以连续)的长度。
其中,这个长度可以用动态规划得到:
- LCS(i, j) = LCS(i-1, j-1)+1 ,当list1[i] == list[j]
- LCS(i, j) = Max(LCS(i-1, j-1), LCS(i-1, j), LCS(i, j-1)),当list1[i] != list[j]
最后,用原字符串的长度减去这个最大公共子串的长度就得到了最小编辑长度。
详情:http://www.cnblogs.com/grenet/archive/2010/06/03/1750454.html
2. 整理数组,大写字母在前,小写字母在后,相对位置不变。——冒泡思想O(n2)
题目:把一个字符串的大写字母放到字符串的后面,各个字符的相对位置不变,且不能申请额外的空间。
输入:输入数据有多组,每组包含一个字符串s,且保证:1<=s.length<=1000.
输出:对于每组数据,输出移位后的字符串。
思路:用冒泡的思想,每一轮遍历,两个数字两两比较,如果前一个元素为小写,后一个元素为大写,则交换。
设置两个指针i,j。i代表遍历的次数: in range( len(list)),j = range(len(list) - 1- i)
def sort_capital_first(data): length = len(data) for i in range(length): for j in range(length- 1-i): # 两两元素比较,如果前一个元素为小写,后一个为大写,则交换 if(not is_capital(data[j]) and is_capital(data[j+1])): data[j], data[j+1] = data[j+1], data[j] print(data)
3. 有n个数,两两组成二元组,差最小的有多少对呢?差最大呢?
——排序:O(nlgn), 统计:O(n)
思路:
1. 对数组进行排序:O(nlgn)
- 特殊情况:所有数字相等,则:
差最大个数 = 差最小个数 = n*(n-1)/2
;(两两组合)
2. 统计数组中每种数字的个数(map)
3. 计算差最小的数:O(n)
-
如果数组中没有重复数字,说明最小差不为
0
,最小差肯定是数组中相邻两个数,
因此,遍历一边数组,计算并统计最小差.
-
如果数组中有重复数字,说明最小差是
0
,此时,遍历一边map,数字个数不为
0
的
数字会产生最小差
0
,个数为n*(n-1)/2
4. 计算最大的数
只有一种情况,最大值与最小值的两两组合,即最大值个数 * 最小值个数
4. 返回数组中数字超过一般的数字——找到中位数O(n)
思路:首先对数组进行排序,找到数组的中位数——即在数组中出现次数超过一半
- 使用随机快排的思想,随机选择一个数作为key,对他进行一次partition,将比他小的数字放在左边,比它大的数字放在右边。
- 比较key的下标,如果等于(n/2),则它是中位数,即是数组中次数超过一半的数字
- 如果<(n/2),则中位数在它的右边,对右边进行递归partition
- 如果>(n/2),则中位数在它的左边,对左边进行递归partition
1. 两个字符串的最大公共子序列——构造回文
题目一:给定一个字符串s,你可以从中删除一些字符,使得剩下的串是一个回文串。如何删除才能使得回文串最长呢?输出需要删除的字符个数。
import sys def max_common_substring(list1, list2): len1 = len(list1) len2 = len(list2) # 使用动态规划: # LCS(i, j) = LCS(i-1, j-1)+1 ,当list1[i] == list[j] # LCS(i, j) = Max(LCS(i-1, j-1), LCS(i-1, j), LCS(i, j-1)),当i!=j # 构建len1*len2矩阵,初始化为0 # 1. 不能使用:data = [[0]*len2]*len1,相当于n个list浅拷贝的连接,改一个数字,改列都发生变化 # 2. 使用: data = [[0] * (len2+1) for i in range(len1+1)] for i in range(len1): for j in range(len2): if(list1[i] == list2[j]): data[i][j] = data[i-1][j-1] + 1 else: data[i][j] = max(data[i-1][j-1], data[i][j-1],data[i-1][j]) return data[len1-1][len2-1] def find_least_delet(str): # 得到list的反转 str_reversed = list(reversed(str)) max_substring_cnt = max_common_substring(str, str_reversed) return len(str) - max_substring_cnt # 若要找出匹配的字符 if __name__ == '__main__': # cmmand+D结束 for line in sys.stdin.readlines(): if(len(line) == 1): break line = line.strip('\n') print(find_least_delet(line))
2. 题目:把一个字符串的大写字母放到字符串的后面,各个字符的相对位置不变,且不能申请额外的空间。
输入:输入数据有多组,每组包含一个字符串s,且保证:1<=s.length<=1000.
输出:对于每组数据,输出移位后的字符串。
def is_capital(char): if(char > 'a' and char < 'z'): return False elif(char > 'A' and char < 'Z'): return True def sort_capital_first(data): length = len(data) for i in range(length): for j in range(length- 1-i): # 两两元素比较,如果前一个元素为小写,后一个为大写,则交换 if(not is_capital(data[j]) and is_capital(data[j+1])): data[j], data[j+1] = data[j+1], data[j] # 转换成字符串输出: string = ''.join(data) print(string) import sys if __name__ == '__main__': data = input() sort_capital_first(list(data))
3. 有n个数,两两组成二元组,差最小的有多少对呢?差最大呢?
import sys if __name__ == '__main__': lines = sys.stdin.readlines() length = int(lines[0].strip('\n')) data = lines[1].strip('\n') data = list(int(x) for x in data.split(' ')) if(length != len(data)): raise IOError('Wrong Input!') if(length == 0): print('0 0') if(length <= 2): print('2 2') # 首先对数组进行排序 data.sort() max_cnt = 0 min_cnt = 0 # 特殊情况: 全部数字相同,则最大差值=最小差值=n*(n-1)/2 if(data[0] == data[-1]): max_cnt = min_cnt = int(length*(length-1)/2) else: # 如果存在相同的数字(dict[index] >1),则最小差值为0, # 对于每个相同的数字:dict[index]*(dict[index]-1)/2) dict = {} same_num = 0 for i in range(length): if data[i] not in dict: dict[data[i]] = 1 else: dict[data[i]] += 1 same_num +=1 max_cnt = dict[data[0]] * dict[data[-1]] # 有相同的数字: if(same_num > 0): for value in dict.values(): min_cnt += int(value*(value-1)/2) # 没有相同的数字: else: differ = [] for i in range(length-1): j = i + 1 differ.append(list[j] - list[i]) # 对differ排序: differ.sort() # 计算最小差的个数: min_diff = differ[0] i = 1 while(differ[i] == min_diff): min_cnt += 1 i += 1 print(min_cnt, ' ', max_cnt)