Google python course basic exercise——list2
list2里面含两个练习,方法多彩多样。
D题实现对list内数据去重操作,E题实现对已排序list实现归并排序,并且要求线性时间复杂度。
题目和代码如下:
1 # D. Given a list of numbers, return a list where 2 # all adjacent == elements have been reduced to a single element, 3 # so [1, 2, 2, 3] returns [1, 2, 3]. You may create a new list or 4 # modify the passed in list. 5 def remove_adjacent(nums): 6 for i in range(len(nums)): #注意边界条件 7 for j in range(len(nums)-1,i,-1):#逆序遍历,当进行删除操作时不会影响待比较元素的序号 8 if nums[i] == nums[j]: 9 nums.remove(nums[j]) 10 return nums 11 12 # E. Given two lists sorted in increasing order, create and return a merged 13 # list of all the elements in sorted order. You may modify the passed in lists. 14 # Ideally, the solution should work in "linear" time, making a single 15 # pass of both lists. 16 def linear_merge(list1, list2): 17 list3=[] 18 while list1 and list2: 19 if list1[-1]>list2[-1]: 20 list3.append(list1.pop()) #pop()默认弹出list最末尾数据操作,时间O(1) 21 else: 22 list3.append(list2.pop()) 23 list3 += (list1+list2)[::-1] 24 list3.reverse() #reverse()built-in类型,时间复杂度为O(N) 25 return list3 26 27 # Simple provided test() function used in main() to print 28 # what each function returns vs. what it's supposed to return. 29 def test(got, expected): 30 if got == expected: 31 prefix = ' OK ' 32 else: 33 prefix = ' X ' 34 print '%s got: %s expected: %s' % (prefix, repr(got), repr(expected)) 35 36 37 # Calls the above functions with interesting inputs. 38 def main(): 39 print 'remove_adjacent' 40 test(remove_adjacent([1, 2, 2, 2, 3]), [1, 2, 3]) 41 test(remove_adjacent([2, 2, 3, 3, 3]), [2, 3]) 42 test(remove_adjacent([]), []) 43 44 print 45 print 'linear_merge' 46 test(linear_merge(['aa', 'xx', 'zz'], ['bb', 'cc']), 47 ['aa', 'bb', 'cc', 'xx', 'zz']) 48 test(linear_merge(['aa', 'xx'], ['bb', 'cc', 'zz']), 49 ['aa', 'bb', 'cc', 'xx', 'zz']) 50 test(linear_merge(['aa', 'aa'], ['aa', 'bb', 'bb']), 51 ['aa', 'aa', 'aa', 'bb', 'bb']) 52 53 if __name__ == '__main__': 54 main()
运行结果:
remove_adjacent OK got: [1, 2, 3] expected: [1, 2, 3] OK got: [2, 3] expected: [2, 3] OK got: [] expected: [] linear_merge OK got: ['aa', 'bb', 'cc', 'xx', 'zz'] expected: ['aa', 'bb', 'cc', 'xx', 'zz'] OK got: ['aa', 'bb', 'cc', 'xx', 'zz'] expected: ['aa', 'bb', 'cc', 'xx', 'zz'] OK got: ['aa', 'aa', 'aa', 'bb', 'bb'] expected: ['aa', 'aa', 'aa', 'bb', 'bb']
ps:
- 关于D题,我借鉴了冒泡排序的思想,利用两轮循环,外层循环负责正序遍历,里层循环负责逆序遍历,判断是否有重复的,有则删除。里层循环一轮结束后,则会删除一个数字的副本。这里强调一下,里层循环必须是逆序的,否则当进行remove()操作时,会改变继续判断时后面元素在list里的index,得不到想要的结果。举例说明:在第一个test case中,nums[1] ==nums[2] 成立,则删除nums[2],nums=[1,2,2,3],搜索nums[3]时得到的是'3',不是第二个'2',显然错误。
- 关于D题,还有个更简单的方法:
1 def remove_adjacent(nums): 2 result = [] 3 for num in nums: 4 if len(result) == 0 or num != result[-1]: 5 result.append(num) 6 return result
其思想为对原list复制时去重,妙在num!=result[-1]这句。
- E题最自然的想法是:
1 def linear_merge(list1, list2): 2 list1.extend(list2) 3 return sorted(list1)
但是,因为python2.3以后的版本使用的是adaptive mergesort algorithm,其时间复杂度为O(nlogn),不合题意。
-
- 为什么不直接用pop(0)呢?因为根据资料显示,pop(0)时间复杂度非constant time(为O(N)),综合考虑用上面方法。
- 答案是丰富多彩的,所以E题还可以这样解:
1 def linear_merge(list1,list2 ): 2 list3 = [] 3 i = j = 0 4 total = len(list1) + len(list2) 5 while len(list3) != total: 6 if len(list1) == i: 7 list3 += list2[j:] 8 break 9 elif len(list2) == j: 10 list3 += list1[i:] 11 break 12 elif list1[i] < list2[j]: 13 list3.append(list1[i]) 14 i += 1 15 else: 16 list3.append(list2[j]) 17 j += 1 18 return list3