1.字符串交换位置
时间复杂度O(n) 空间复杂度O(1)
输入 "abcde" 输出 "edcba"
def jiaohuan(str1): s1 = list(str1) tmp = 0 for i in range(0, int(len(s1) / 2)): tmp = s1[i] s1[i] = s1[len(s1) - i - 1] s1[len(s1) - i - 1] = tmp return s1 list1 = jiaohuan("abcde") print("".join(list1)) # edcba
2.数组找最大值、最小值
定义了一个数组a = [1,3,4,55,29] 查找数组中最大值
定义一个for循环对数组所有元素遍历一遍时间复杂度为O(n)
def max_value(l1): min = -1 max = -1 for i in range(len(l1)): if l1[i] > max: max = l1[i] min = i print(max) max_value([1, 2, 333, 4, 5, -1])
3.降低复杂度案例、 输入数组a = [1,2,3,4,5,6,4,4,4,2] 中查找出现次数最多的数值
def max_count(l1): d1 = {} for i in l1: d1[i] = d1.get(i, 0) + 1 print(d1) max_key = -1 count_num = -1 for i, v in d1.items(): if v > count_num: count_num = v max_key = i print(max_key, count_num) max_count([1, 2, 3, 4, 5, 6, 4, 4, 4, 4])
4.栈:后进先出 给定一个只包括 ‘(‘,‘)‘,‘{‘,‘}‘,‘[‘,‘]‘ 的字符串,判断字符串是否有效。
class Solution: def isValid(self, s: str) -> bool: len_s = len(s) if len_s % 2 != 0: return False if len_s == 0: return True # 利用进栈出栈的思想 str_dict = {‘(‘: ‘)‘, ‘[‘: ‘]‘, ‘{‘: ‘}‘} stacked = [] for i in range(len_s): # 如果符号为左括号进行压栈 if s[i] in str_dict.keys(): stacked.append(s[i]) # 如果栈不为空且符号在右括号内且左符号和最后一个元素相等 if stacked and s[i] in str_dict.values() and s[i] == str_dict[stacked[-1]]: stacked.pop() if stacked == []: return True else: return False solution = Solution() print(solution.isValid("{[]}")) # True print(solution.isValid("{[[}")) # False
5.为支持浏览器前进和后退功能,利用栈记录历史访问信息 后进先出
first_list = [] last_list = [] def chrome_a(url): if url not in last_list and url not in first_list: # 当用户访问一个新页面 last_list.append(url) elif url in last_list: # 当用户后退一个页面 last_list.pop() first_list.append(url) else: # 用户前进一个页面 first_list.pop() last_list.append(url) for url in [1, 2, 3, 4, 5, 5, 4, 3, 4]: chrome_a(url) print(first_list) print(last_list)
6.队列 先进先出
def josephus2(num, k, m): alist = list(range(1, num + 1)) index, step = k - 1, m # 从1号开始报数,数到3的那个人出列 for i in range(num - 1): index = (index + step - 1) % len(alist) print(‘出去的数:‘, alist.pop(index)) return ‘最后的一个数:%s‘ % alist[0] print(josephus2(13, 1, 3))
7.数组 数组在内存中是连续存放的,数组内的数据,可以通过索引值直接取出得到
数组 [1,4,3,5,2] 去掉一个最大值和最小值求平均数 要求不允许开辟O(n)空间复杂度的数据结构
def score_avge(l1): max_num = -1 max_number = -1 min_num = -1 min_number = 99 for index, value in enumerate(l1): if value > max_number: max_number = value max_num = index if min_number > value: min_number = value min_num = index print(min_num, max_num) del l1[max_num] del l1[min_num] scores = 0 for i, v in enumerate(l1): scores += v print("平均分:{}".format(scores / len(l1))) score_avge([1, 4, 3, 5, 2])
8.字符串 操作都是On
字符串替换将a替换为1aa替换为2 abaabccdaab==>1b2bccd2b
for i in s1: if i == "a": count += 1 else: if count != 0: s2 += str(count) count = 0 s2 += i print(s2)
9. 字符串 s = "goodgoogle",判断字符串 t = "google" 在 s 中是否存在
s = "goodgoogle1ccc" t = "google" status = True num = 0 for i, v in enumerate(s): if v == t[num]: status = True num += 1 if len(t) == num: break else: status = False num = 0 if status: print("t字符串在s中") else: print("t字符串不在s中")
10.设置有且有两个字符串a = "1345239" b = "12345" 由于"345"同时出现在a和b中因此输出345
def getMaxCommonSubstr(s1, s2): # 求两个字符串的最长公共子串 # 思想:建立一个二维数组,保存连续位相同与否的状态 len_s1 = len(s1) len_s2 = len(s2) # 生成0矩阵,为方便后续计算,多加了1行1列 # 行: (len_s1+1) # 列: (len_s2+1) record = [[0 for i in range(len_s2 + 1)] for j in range(len_s1 + 1)] print(record) maxNum = 0 # 最长匹配长度 p = 0 # 字符串匹配的终止下标 for i in range(len_s1): for j in range(len_s2): if s1[i] == s2[j]: # 相同则累加 record[i + 1][j + 1] = record[i][j] + 1 if record[i + 1][j + 1] > maxNum: maxNum = record[i + 1][j + 1] p = i # 匹配到下标i # 返回 子串长度,子串 return maxNum, s1[p + 1 - maxNum: p + 1] print(getMaxCommonSubstr("1345239", "12345"))
11.二叉树 树的遍历方法:前序遍历、中序遍历、后序遍历
# 递归的核心思想是把规模大的问题转换为规模小的相似的子问题 def move(n, a, b, c): if n == 1: print(‘%s-->%s‘ % (a, c)) else: move(n - 1, a, c, b) print(‘%s-->%s‘ % (a, c)) move(n - 1, b, a, c) move(3, ‘A‘, ‘B‘, ‘C‘)
12.分治法、二分查找
l1 = [i for i in range(0, 9)] print("查找列表为:{}".format(l1)) start = 0 end = len(l1) - 1 number = 5 while True: middle = (start + end) // 2 if number == l1[middle]: print("索引位置为:{}".format(middle)) break elif number > l1[middle]: start = middle + 1 elif number < l1[middle]: end = middle - 1 if start > end: print("没找到") break
13.在一个有序数组里面,查找出第一个大于9的数字,假设一定存在
l1 = [-1, 3, 3, 7, 10, 14, 14] start = 0 end = len(l1) - 1 number = 9 while True: middle = (start + end) // 2 if l1[middle] > number and l1[middle - 1] < number: print("第一个比{}大的数字是:{}".format(number, l1[middle])) break elif number > l1[middle]: start = middle + 1 elif number < l1[middle]: end = middle - 1 if start > end: break
14.排序 -- 二分查找必须为有序 常见4种排序:冒泡排序、插入排序、归并排序、以及快速排序
冒泡排序:空间复杂度为O(1) 时间复杂度O(n*n)
l1 = [1, 0, -1, 22, 33, 99, 76, 54] for j in range(0, len(l1)): for i in range(0, len(l1) - 1 - j): if l1[i] < l1[i + 1]: l1[i], l1[i + 1] = l1[i + 1], l1[i] print("排序后的列表:{}".format(l1))
插入排序空间复杂度是O(1) 最好的时间复杂度O(n) 最坏的时间复杂度O(n*n)
l2 = [1, 0, -1, 22, 33, 99, 76, 54] for i in range(1, len(l2)): for j in ran ge(i, 0, -1): if l2[j] < l2[j - 1]: l2[j], l2[j - 1] = l2[j - 1], l2[j] else: break print("排序后的列表:{}".format(l2))
归并排序
归并排序采用二分的迭代方式,复杂度是logn
合并两列表
def merge(a, b): # a,b是待合并的两个列表,两个列表分别都是有序的,合并后才会有序 merged = [] i, j = 0, 0 while i < len(a) and j < len(b): if a[i] <= b[j]: merged.append(a[i]) i += 1 else: merged.append(b[j]) j += 1 merged.extend(a[i:]) merged.extend(b[j:]) return merged
# 递归操作
def merge_sort(c): if len(c) <= 1: return c mid = len(c) // 2 # 除法取整 a = merge_sort(c[:mid]) b = merge_sort(c[mid:]) return merge(a, b) c = [7, 9, 1, 0, 4, 3, 8, 2, 5, 4, 6] print(merge_sort(c))
快速排序法 稳定性较差
左小右大函数,获取一个中值,左放小右放大函数
def partition(arr, low, high): # 参数:列表,列表的第一个索引0,最后一个索引值N """ 【左小右大函数】 实现结果:提取列表中的最后一个元素为被比较值,≤该元素的值放在左边,>该元素的值放在右边 实现过程:≤最后一个元素的所有元素依次放在左边索引0~i的位置,然后将最后一个元素放在索引i的位置,实现结果 arr: 列表 low: arr的第一个索引:0 high: arr的最后一个索引:high return: i,即被比较值所在的索引位置 """ i = low # 最小元素索引 pivot = arr[high] # 最后一个元素,我们把列表中的所有元素同它比较 for j in range(low, high): # 从第一个索引到倒数第二个索引 if arr[j] <= pivot: # 从第一个元素到倒数第二个元素依次判断是否≤最后一个元素 arr[i], arr[j] = arr[j], arr[i] # ≤最后一个元素的所有元素依次放在左边索引0~i的位置 i = i + 1 arr[i], arr[high] = arr[high], arr[i] # 然后将最后一个元素放在索引i的位置,实现:该元素左边的都比它小,右边的都比它大的排序 return (i) # 返回该元素的索引位置 # 快速排序函数 def quickSort(arr, low, high): if low < high: # 如果列表有1个以上的元素 pi = partition(arr, low, high) # 获取左小右大函数中的 被比较数所在的索引 quickSort(arr, low, pi - 1) # 反复循环,左排序 quickSort(arr, pi + 1, high) # 反复循环,右排序 arr = [10, 22, 78, 3, 12, 9, 1, 11, 33, 2] low = 0 high = len(arr) - 1 quickSort(arr, low, high) print(arr)
15.动态规划是一种运筹学方法,是在多轮决策过程中的最优方法
16.在一个数组 a = [1, 3, 4, 3, 4, 1, 3] 中,找到出现次数最多的那个数字。如果并列存在多个,随机输出一个。
a = [1, 3, 4, 3, 4, 1, 3] d1 = {} for i in a: d1[i] = d1.get(i, 0) + 1 print(d1) max_count = -1 max_value = -1 for i, v in d1.items(): if v > max_count: max_count = v max_value = i print("出现次数最多的数字:{} 次数为:{}".format(max_value, max_count))
17.这个问题是力扣的经典问题,two sums。给定一个整数数组 arr 和一个目标值 target,请你在该数组中找出加和等于目标值的两个整数,并返回它们在原数组中的下标。
arr = [1, 2, 3, 4, 5, 6],target = 4。因为,arr[0] + arr[2] = 1 + 3 = 4 = target,则输出 0,2。
l1 = [1, 2, 3, 4, 5, 6, 10] target = 10 d1 = {} for i, v in enumerate(l1): d1[target - v] = i print(d1) # {3: 0, 2: 1, 1: 2, 0: 3, -1: 4, -2: 5} result = [] for i in range(0, len(l1)): # 相减得到另一个数值 num1 = target - l1[i] num2 = target - num1 if num1 in d1 and num2 in d1: print(d1[num1], d1[num2]) break
18.递归 斐波那契数列是:0,1,1,2,3,5,8,13,21,34,55,89,144……。
你会发现,这个数列中元素的性质是,某个数等于它前面两个数的和;
也就是 a[n+2] = a[n+1] + a[n]。至于起始两个元素,则分别为 0 和 1。在这个数列中的数字,就被称为斐波那契数。
【题目】写一个函数,输入 x,输出斐波那契数列中第 x 位的元素。
例如,输入 4,输出 2;输入 9,输出 21。要求:需要用递归的方式来实现。
def fun(x): if x == 1: return 0 if x == 2: return 1 return fun(x - 1) + fun(x - 2) def fb_main(x): print(fun(x)) fb_main(4)
19.给定一个字符串,逐个翻转字符串中的每个单词。
例如,输入:"This is a good example",
输出:"example good a is This"。如果有多余的空格需要删除。
栈 后进先出
l1 = "This is a good example".split(" ") print(l1) l2 = [] new_str = "" for i in l1: l2.append(i) print(l2) n = 0 while l2: if n == 0: new_str += l2.pop() else: new_str += " " + l2.pop() n += 1 print(new_str)
20.
【题目】 给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,
返回移除后的数组和新的长度,你不需要考虑数组中超出新长度后面的元素。
要求:空间复杂度为 O(1),即不要使用额外的数组空间。
例如,给定数组 nums = [1,1,2],函数应该返回新的长度2,并且原数组 nums 的前两个元素被修改为 1, 2。
又如,给定 nums = [0,0,1,1,1,2,2,3,3,4],函数应该返回新的长度 5,并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。
nums = [0, 0, 1, 1, 1, 2, 2, 3, 3, 4] index = 1 for i in range(len(nums) - 1): if nums[index] == nums[index - 1]: del nums[index] else: index += 1 print(len(nums)) print(nums)
21.例题 1:判断数组中所有的数字是否只出现一次
arr = {1, 2, 3},输出 YES。又如,arr = {1, 2, 1},输出 NO。
arr = [1, 2, 3, 1] d1 = {} status = True for i in arr: if not d1.get(i): d1[i] = 1 status = True else: status = False break print(status)
22.找出数组中出现次数超过数组长度一半的元素你可以假设一定存在这个出现次数超过数组长度的一半的数字,即不用考虑输入不合法的情况。
要求时间复杂度是 O(n),空间复杂度是 O(1)。例如,输入 a = {1,2,1,1,2,4,1,5,1},输出 1。
a = [1, 2, 2, 2, 2, 2, 1, 5, 1] result = a[0] times = 1 for i in range(len(a)): if a[i] != result: times -= 1 else: times += 1 if times == -1: times = 1 result = a[i] print(result)