剑指Offer-Python题解(三)
45 扑克牌顺子
题目描述
LL今天心情特别好,因为他去买了一副扑克牌,发现里面居然有2个大王,2个小王(一副牌原本是54张^_^)...他随机从中抽出了5张牌,想测测自己的手气,看看能不能抽到顺子,如果抽到的话,他决定去买体育彩票,嘿嘿!!“红心A,黑桃3,小王,大王,方片5”,“Oh My God!”不是顺子.....LL不高兴了,他想了想,决定大\小 王可以看成任何数字,并且A看作1,J为11,Q为12,K为13。上面的5张牌就可以变成“1,2,3,4,5”(大小王分别看作2和4),“So Lucky!”。LL决定去买体育彩票啦。 现在,要求你使用这幅牌模拟上面的过程,然后告诉我们LL的运气如何, 如果牌能组成顺子就输出true,否则就输出false。为了方便起见,你可以认为大小王是0。
解题思路
代码
# -*- coding:utf-8 -*-
# LL今天心情特别好,因为他去买了一副扑克牌,发现里面居然有2个大王,
# 2个小王(一副牌原本是54张^_^)...他随机从中抽出了5张牌,想测测自己的手气,
# 看看能不能抽到顺子,如果抽到的话,他决定去买体育彩票,嘿嘿!!
# “红心A,黑桃3,小王,大王,方片5”,“Oh My God!”不是顺子.....LL不高兴了,
# 他想了想,决定大\小 王可以看成任何数字,并且A看作1,J为11,Q为12,K为13。
# 上面的5张牌就可以变成“1,2,3,4,5”(大小王分别看作2和4),“So Lucky!”。
# LL决定去买体育彩票啦。 现在,要求你使用这幅牌模拟上面的过程,
# 然后告诉我们LL的运气如何, 如果牌能组成顺子就输出true,否则就输出false。
# 为了方便起见,你可以认为大小王是0。
class Solution:
def IsContinuous(self, numbers):
if not numbers:
return 0
numbers.sort()
zeros = numbers.count(0)
for i, v in enumerate(numbers[:-1]):
if v != 0:
if numbers[i + 1] == v:
return False
zeros -= (numbers[i + 1] - numbers[i] - 1)
if zeros < 0:
return False
return True
if __name__ == '__main__':
S = Solution()
print(S.IsContinuous([1, 2, 3, 4, 5, 6, 7, 0]))
46 孩子们的游戏-圆圈中最后剩下的数
题目描述
每年六一儿童节,牛客都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此。HF作为牛客的资深元老,自然也准备了一些小游戏。其中,有个游戏是这样的:首先,让小朋友们围成一个大圈。然后,他随机指定一个数m,让编号为0的小朋友开始报数。每次喊到m-1的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续0...m-1报数....这样下去....直到剩下最后一个小朋友,可以不用表演,并且拿到牛客名贵的“名侦探柯南”典藏版(名额有限哦!!^_^)。请你试着想下,哪个小朋友会得到这份礼品呢?(注:小朋友的编号是从0到n-1) 如果没有小朋友,请返回-1
解题思路
代码
# -*- coding:utf-8 -*-
# 每年六一儿童节,牛客都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此。
# HF作为牛客的资深元老,自然也准备了一些小游戏。
# 其中,有个游戏是这样的:首先,让小朋友们围成一个大圈。
# 然后,他随机指定一个数m,让编号为0的小朋友开始报数。
# 每次喊到m-1的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,
# 并且不再回到圈中,从他的下一个小朋友开始,
# 继续0...m-1报数....这样下去....直到剩下最后一个小朋友,
# 可以不用表演,并且拿到牛客名贵的“名侦探柯南”典藏版(名额有限哦!!^_^)。
# 请你试着想下,哪个小朋友会得到这份礼品呢?(注:小朋友的编号是从0到n-1)
class Solution:
def LastRemaining_Solution(self, n, m):
if n == 0 and m == 0:
return -1
stu = list(range(0, n))
cur = 0
while len(stu) > 1:
cur = (cur + m - 1) % len(stu)
stu.pop(cur)
return stu[0]
if __name__ == '__main__':
S = Solution()
print(S.LastRemaining_Solution(10, 5))
47 求1+2+3+...+n
题目描述
求1+2+3+...+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。
解题思路
代码
# -*- coding:utf-8 -*-
# 求1+2+3+...+n,要求不能使用乘除法、for、while、if、else、switch、case等
# 关键字及条件判断语句(A?B:C)。
class Solution:
def Sum_Solution(self, n):
if n == 1:
return 1
else:
return n + self.Sum_Solution(n - 1)
if __name__ == '__main__':
S = Solution()
print(S.Sum_Solution(100))
48 不用加减乘除做加法
题目描述
写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。
解题思路
代码
# -*- coding:utf-8 -*-
# 求1 + 2 + 3 + ... + n,要求不能使用乘除法、for、while、if、else、switch、case等
# 关键字及条件判断语句(A ? B : C)
# 思路:
# 不计进位的和为 a ^ b,进位就是 a & b
# a + b = a ^ b + (a & b) << 1
class Solution:
def Add_sum(self, num1, num2):
num = [num1, num2]
return sum(num)
def Add(self, num1, num2):
unit = num1 ^ num2
carry_bit = num1 & num2
while carry_bit != 0:
temp_a = unit
temp_b = carry_bit << 1
unit = temp_a ^ temp_b
carry_bit = temp_a & temp_b
return unit
if __name__ == '__main__':
S = Solution()
print(S.Add(100, 12))
49 把字符串转换成整数
题目描述
将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0
输入描述
输入一个字符串,包括数字字母符号,可以为空
输出描述
如果是合法的数值表达则返回该数字,否则返回0
示例1
输入
+2147483647
1a33
输出
2147483647
0
解题思路
代码
# -*- coding:utf-8 -*-
# 将一个字符串转换成一个整数(实现Integer.valueOf(string)的功能,
# 但是string不符合数字要求时返回0),要求不能使用字符串转换整数的库函数。
# 数值为0或者字符串不是一个合法的数值则返回0。
class Solution:
def StrToInt(self, s):
flag = True
pos = 1
res = 0
if s == '':
return 0
for i in s:
if i == '+' or i == '-':
if flag == True:
flag = False
if i == '+':
pos = 1
elif i == '-':
pos = -1
else:
return 0
else:
return 0
elif i >= '0' and i <= '9':
flag = False
res = res * 10 + int(i)
else:
return 0
res = pos * res
return res
S = Solution()
print(S.StrToInt('1234'))
50 数组中重复的数字
题目描述
在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。
解题思路
代码
# -*- coding:utf-8 -*-
# 在一个长度为n的数组里的所有数字都在0到n-1的范围内。
# 数组中某些数字是重复的,但不知道有几个数字是重复的。
# 也不知道每个数字重复几次。请找出数组中任意一个重复的数字。
# 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},
# 那么对应的输出是第一个重复的数字2。
class Solution:
def duplicate(self, numbers, duplication):
dic = {}
if not numbers:
return False
for i in numbers:
if i not in dic:
dic[i] = 1
else:
if dic[i] == 1:
duplication[0] = i
return True
return False
"""
举例说明:{2,3,1,0,2,5,3}:
0(索引值)和2(索引值位置的元素)不相等,
并且2(索引值位置的元素)和1(以该索引值位置的元素2为索引值的位置的元素)不相等,
则交换位置,数组变为:{1,3,2,0,2,5,3};
0(索引值)和1(索引值位置的元素)仍然不相等,
并且1(索引值位置的元素)和3(以该索引值位置的元素1为索引值的位置的元素)不相等,
则交换位置,数组变为:{3,1,2,0,2,5,3};
0(索引值)和3(索引值位置的元素)仍然不相等,
并且3(索引值位置的元素)和0(以该索引值位置的元素3为索引值的位置的元素)不相等,
则交换位置,数组变为:{0,1,2,3,2,5,3};
0(索引值)和0(索引值位置的元素)相等,遍历下一个元素;
1(索引值)和1(索引值位置的元素)相等,遍历下一个元素;
2(索引值)和2(索引值位置的元素)相等,遍历下一个元素;
3(索引值)和3(索引值位置的元素)相等,遍历下一个元素;
4(索引值)和2(索引值位置的元素)不相等,
但是2(索引值位置的元素)和2(以该索引值位置的元素2为索引值的位置的元素)相等,
则找到了第一个重复的元素。
"""
class Solution1:
def duplicate(self, numbers, duplication):
n = len(numbers)
if n == 0:
return False
for i in range(n):
if numbers[i] < 0 or numbers[i] > n - 1:
return False
for i in range(n):
while numbers[i] != i:
if numbers[i] == numbers[numbers[i]]:
duplication[0] = numbers[i]
return True
numbers[numbers[i]], numbers[i] = numbers[i], numbers[numbers[i]]
return False
class Solution2:
def duplicate(self, numbers, duplication):
n = len(numbers)
if n == 0:
return False
for i in range(n):
index = numbers[i]
if index >= n:
index -= n
if numbers[index] >= n:
duplication[0] = index
return True
numbers[index] += n
return False
if __name__ == '__main__':
S = Solution1()
res = [1]
print(S.duplicate([2, 1, 3, 1, 4], res))
print(res)
51 构建乘积数组
题目描述
给定一个数组A[0,1,...,n-1],请构建一个数组B[0,1,...,n-1],其中B中的元素B[i]=A[0]A[1]...A[i-1]A[i+1]...A[n-1]。不能使用除法。
解题思路
代码
# -*- coding:utf-8 -*-
# 给定一个数组A[0,1,...,n-1],请构建一个数组B[0,1,...,n-1],
# 其中B中的元素B[i]=A[0]*A[1]*...*A[i-1]*A[i+1]*...*A[n-1]。
# 不能使用除法。
class Solution:
def multiply(self, A):
size = len(A)
B = [1] * size
# 下三角: B[i]=A[0]A[1]A[2]..A[i−1] = B[i−1]A[i−1]
for i in range(1, size):
B[i] = B[i - 1] * A[i - 1]
tmp = 1
# 上三角(从最后往前)tmp=A[−1]A[−2]A[−3]...
for i in range(size - 2, -1, -1):
tmp = tmp * A[i + 1]
B[i] = B[i] * tmp
return B
if __name__ == '__main__':
S = Solution()
print(S.multiply([2, 1, 3, 1, 4]))
52 正则表达式匹配
题目描述
请实现一个函数用来匹配包括'.'和''的正则表达式。模式中的字符'.'表示任意一个字符,而''表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"abaca"匹配,但是与"aa.a"和"ab*a"均不匹配
解题思路
代码
# -*- coding:utf-8 -*-
# 请实现一个函数用来匹配包括'.'和'*'的正则表达式。
# 模式中的字符'.'表示任意一个字符,
# 而'*'表示它前面的字符可以出现任意次(包含0次)。
# 在本题中,匹配是指字符串的所有字符匹配整个模式。
# 例如,字符串"aaa"与模式"a.a"和"ab*ac*a"匹配,
# 但是与"aa.a"和"ab*a"均不匹配
class Solution:
# s和pattern都是字符串
def match(self, s, pattern):
# s和pattern都为空
if not s and not pattern:
return False
# s和pattern直接匹配
if s == pattern:
return True
# 当s为'', 如果pattern为'.',则返回True
# 当s为'', 如果pattern长度为1且不为'.', 或者pattern第二个字符不是*, 则pattern不可能为空, 返回False
# 若pattern长度不为1, 且第二个字符为*, pattern还有空的可能, 从第三个字符开始迭代
elif s == '':
if pattern == '.':
return True
elif len(pattern) == 1 or pattern[1] != '*':
return False
else:
return self.match(s, pattern[2:])
# 如果pattern长度不小于二, 而且pattern的第二个字符不是*的情况下
# 当 pattern[0] 不等于s[0], 且不为 . 的时候, s和pattern必不相等
# 否则, s 和 pattern 都右移一位, 继续比较
if len(pattern) >= 2 and pattern[1] != '*':
if s[0] != pattern[0] and pattern[0] != '.':
return False
else:
return self.match(s[1:], pattern[1:])
# 如果pattern长度不小于2, 且pattern第二个字符为*的情况下
# 如果s[0]不等于pattern[0], 且pattern[0]不为 . , 那么第一位比较不成功,
# pattern必须后移两位继续比较后面是否能和s第一位匹配
# 如果s[0]等于pattern[0], 或者pattern[0]为 . , 第一位匹配, 那么会有
# 1. aaa 和 a*a 这种情况, 星号代表了多个a, 因此s需要不断右移一位继续比较
# 2. a 和 a*a 中这情况, 这时候星号代表0个a, 因此s不需要右移, pattern需要右移两位
# 3. abc 和 a*bc 这种情况, 星号代表了1个a, s右移一位, pattern右移两位继续比较
elif len(pattern) >= 2 and pattern[1] == '*':
if s[0] != pattern[0] and pattern[0] != '.':
return self.match(s, pattern[2:])
else:
return self.match(s[1:], pattern) or self.match(s, pattern[2:]) or self.match(s[1:], pattern[2:])
# 除去上述pattern不小于2情况, 只剩下pattern等于1的情况, 因此如果pattern为".", 而且s长度为1, 返回True
elif pattern == '.' and len(s) == 1:
return True
return False
class Solution1:
# s, pattern都是字符串
def __init__(self):
self.dic = {}
def match(self, s, p):
if (s, p) in self.dic:
return self.dic[(s, p)]
if p == '':
return s == ''
if len(p) == 1 or p[1] != '*':
self.dic[(s[1:], p[1:])] = self.match(s[1:], p[1:])
return len(s) > 0 and (p[0] == '.' or p[0] == s[0]) and self.dic[(s[1:], p[1:])]
while len(s) and (p[0] == '.' or p[0] == s[0]):
self.dic[(s, p[2:])] = self.match(s, p[2:])
if self.match(s[:], p[2:]):
return True
s = s[1:]
self.dic[(s, p[2:])] = self.match(s, p[2:])
return self.dic[(s, p[2:])]
if __name__ == '__main__':
S = Solution1()
print(S.match('aaa', 'a*a'))
53 表示数值的字符串
题目描述
请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+100","5e2","-123","3.1416"和"-1E-16"都表示数值。 但是"12e","1a3.14","1.2.3","+-5"和"12e+4.3"都不是。
解题思路
代码
# -*- coding:utf-8 -*-
# 请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。
# 例如,字符串"+100","5e2","-123","3.1416"和"-1E-16"都表示数值。
# 但是"12e","1a3.14","1.2.3","+-5"和"12e+4.3"都不是。
class Solution:
def isNumeric(self, s):
isAllowDot = True
isAllowE = True
for i in range(len(s)):
if s[i] in "+-" and (i == 0 or s[i - 1] in "eE") and i < len(s) - 1:
continue
elif isAllowDot and s[i] == ".":
isAllowDot = False
if i >= len(s) - 1 or s[i + 1] not in "0123456789":
return False
elif isAllowE and s[i] in "Ee":
isAllowDot = False
isAllowE = False
if i >= len(s) - 1 or s[i + 1] not in "0123456789+-":
return False
elif s[i] not in "0123456789":
return False
return True
class Solution1:
# s字符串
def isNumeric(self, s):
INVALID = 0
SPACE = 1
SIGN = 2
DIGIT = 3
DOT = 4
EXPONENT = 5
# 0invalid, 1space, 2sign, 3digit, 4dot, 5exponent, 6num_inputs
transitionTable = [[-1, 0, 3, 1, 2, -1], # 0 no input or just spaces
[-1, 8, -1, 1, 4, 5], # 1 input is digits
[-1, -1, -1, 4, -1, -1], # 2 no digits in front just Dot
[-1, -1, -1, 1, 2, -1], # 3 sign
[-1, 8, -1, 4, -1, 5], # 4 digits and dot in front
[-1, -1, 6, 7, -1, -1], # 5 input 'e' or 'E'
[-1, -1, -1, 7, -1, -1], # 6 after 'e' input sign
[-1, 8, -1, 7, -1, -1], # 7 after 'e' input digits
[-1, 8, -1, -1, -1, -1]] # 8 after valid input input space
state = 0
i = 0
while i < len(s):
inputtype = INVALID
if s[i] == ' ':
inputtype = SPACE
elif s[i] == '-' or s[i] == '+':
inputtype = SIGN
elif s[i] in '0123456789':
inputtype = DIGIT
elif s[i] == '.':
inputtype = DOT
elif s[i] == 'e' or s[i] == 'E':
inputtype = EXPONENT
state = transitionTable[state][inputtype]
if state == -1:
return False
else:
i += 1
return state == 1 or state == 4 or state == 7 or state == 8
if __name__ == '__main__':
S = Solution()
print(S.isNumeric('-1234'))
54 字符流中第一个不重复的字符
题目描述
请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g"。当从该字符流中读出前六个字符“google"时,第一个只出现一次的字符是"l"。
输出描述:
如果当前字符流没有存在出现一次的字符,返回#字符。
解题思路
代码
# -*- coding:utf-8 -*-
# 请实现一个函数用来找出字符流中第一个只出现一次的字符。
# 例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g"。
# 当从该字符流中读出前六个字符“google"时,第一个只出现一次的字符是"l"。
class Solution:
def __init__(self):
self.queue = []
self.memory = dict()
# 返回对应char
def FirstAppearingOnce(self):
while len(self.queue) and self.memory[self.queue[0]] > 1:
self.queue.pop(0)
return self.queue[0] if len(self.queue) else '#'
def Insert(self, char):
if char not in self.memory:
self.memory[char] = 0
self.memory[char] += 1
if self.memory[char] == 1:
self.queue.append(char)
if __name__ == '__main__':
S = Solution()
S.Insert('1')
S.Insert('2')
S.Insert('1')
S.Insert('1')
print(S.FirstAppearingOnce())
55 链表中环的入口结点
题目描述
给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。
解题思路
代码
# coding:utf-8
# 给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null
class Node(object):
"""节点"""
def __init__(self, elem):
self.elem = elem
self.next = None
class SingleLinkList(object):
"""单链表"""
def __init__(self, node=None):
self.__head = node
def is_empty(self):
"""链表是否为空"""
return self.__head == None
def length(self):
"""链表长度"""
# cur游标,用来移动遍历节点
cur = self.__head
# count记录数量
count = 0
while cur != None:
count += 1
cur = cur.next
return count
def travel(self):
"""遍历整个链表"""
cur = self.__head
while cur != None:
print(cur.elem, end=" ")
cur = cur.next
print("")
def add(self, item):
"""链表头部添加元素,头插法"""
node = Node(item)
node.next = self.__head
self.__head = node
def append(self, item):
"""链表尾部添加元素, 尾插法"""
node = Node(item)
if self.is_empty():
self.__head = node
else:
cur = self.__head
while cur.next != None:
cur = cur.next
cur.next = node
def insert(self, pos, item):
"""指定位置添加元素
pos 从0开始
"""
if pos <= 0:
self.add(item)
elif pos > (self.length() - 1):
self.append(item)
else:
pre = self.__head
count = 0
while count < (pos - 1):
count += 1
pre = pre.next
# 当循环退出后,pre指向pos-1位置
node = Node(item)
node.next = pre.next
pre.next = node
def remove(self, item):
"""删除节点"""
cur = self.__head
pre = None
while cur != None:
if cur.elem == item:
# 先判断此结点是否是头节点
# 头节点
if cur == self.__head:
self.__head = cur.next
else:
pre.next = cur.next
break
else:
pre = cur
cur = cur.next
def search(self, item):
"""查找节点是否存在"""
cur = self.__head
while cur != None:
if cur.elem == item:
return True
else:
cur = cur.next
return False
def Loop(self):
"""链表尾部指向头"""
if self.is_empty():
self.__head = self.__head
else:
cur = self.__head
while cur.next != None:
cur = cur.next
cur.next = self.__head
def EntryNodeOfLoop(self):
head = self.__head
if head == None or head.next == None:
return None
slow = fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
if slow == fast:
fast = head
while fast != slow:
fast = fast.next
slow = slow.next
return fast
return None
if __name__ == "__main__":
ll = SingleLinkList()
ll.append(1)
ll.append(2)
ll.append(3)
ll.append(4)
ll.append(5)
ll.append(6)
ll.travel()
ll.Loop()
res = ll.EntryNodeOfLoop()
print(res.elem)
56 删除链表中重复的结点
题目描述
在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5
解题思路
代码
# coding:utf-8
# 在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,
# 重复的结点不保留,返回链表头指针。
# 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5
class Node(object):
"""节点"""
def __init__(self, elem):
self.elem = elem
self.next = None
class SingleLinkList(object):
"""单链表"""
def __init__(self, node=None):
self.__head = node
def is_empty(self):
"""链表是否为空"""
return self.__head == None
def length(self):
"""链表长度"""
# cur游标,用来移动遍历节点
cur = self.__head
# count记录数量
count = 0
while cur != None:
count += 1
cur = cur.next
return count
def travel(self):
"""遍历整个链表"""
cur = self.__head
while cur != None:
print(cur.elem, end=" ")
cur = cur.next
print("")
def add(self, item):
"""链表头部添加元素,头插法"""
node = Node(item)
node.next = self.__head
self.__head = node
def append(self, item):
"""链表尾部添加元素, 尾插法"""
node = Node(item)
if self.is_empty():
self.__head = node
else:
cur = self.__head
while cur.next != None:
cur = cur.next
cur.next = node
def insert(self, pos, item):
"""指定位置添加元素
pos 从0开始
"""
if pos <= 0:
self.add(item)
elif pos > (self.length() - 1):
self.append(item)
else:
pre = self.__head
count = 0
while count < (pos - 1):
count += 1
pre = pre.next
# 当循环退出后,pre指向pos-1位置
node = Node(item)
node.next = pre.next
pre.next = node
def remove(self, item):
"""删除节点"""
cur = self.__head
pre = None
while cur != None:
if cur.elem == item:
# 先判断此结点是否是头节点
# 头节点
if cur == self.__head:
self.__head = cur.next
else:
pre.next = cur.next
break
else:
pre = cur
cur = cur.next
def search(self, item):
"""查找节点是否存在"""
cur = self.__head
while cur != None:
if cur.elem == item:
return True
else:
cur = cur.next
return False
def get_head(self):
return self.__head
class Solution:
def deleteDuplication(self, pHead):
if pHead == None or pHead.next == None:
return pHead
dummy = Node(0)
dummy.next = pHead
pre = dummy
cur = dummy.next
while cur != None:
while cur.next and cur.next.elem == pre.next.elem:
cur = cur.next
if pre.next == cur:
pre = pre.next
else:
pre.next = cur.next
cur = cur.next
return dummy.next
if __name__ == "__main__":
ll = SingleLinkList()
ll.append(1)
ll.append(1)
ll.append(3)
ll.append(4)
ll.append(5)
ll.append(6)
ll.travel()
S = Solution()
ll_res = SingleLinkList(S.deleteDuplication(ll.get_head()))
ll_res.travel()
57 二叉树的下一个结点
题目描述
给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
解题思路
代码
# -*- coding:utf-8 -*-
# 给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。
# 注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
class TreeLinkNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
self.next = None
# 分三种情况:
# a. 如果该结点存在右子结点,那么该结点的下一个结点是右子结点树上最左子结点
# b. 如果该结点不存在右子结点,且它是它父结点的左子结点,那么该结点的下一个结点是它的父结点
# c. 如果该结点既不存在右子结点,且也不是它父结点的左子结点,则需要一路向祖先结点搜索,
# 直到找到一个结点,该结点是其父亲结点的左子结点。如果这样的结点存在,
# 那么该结点的父亲结点就是我们要找的下一个结点。
class Solution:
def GetNext(self, pNode):
if pNode == None:
return None
# case a
if pNode.right:
tmp = pNode.right
while (tmp.left):
tmp = tmp.left
return tmp
p = pNode.next
while (p and p.right == pNode):
pNode = p
p = p.next
return p
if __name__ == "__main__":
S = Solution()
node = TreeLinkNode(1)
node1 = TreeLinkNode(2)
node2 = TreeLinkNode(3)
node3 = TreeLinkNode(4)
node.left = node1
node.right = node2
node.next = node3
print(S.GetNext(node).val)
58 对称的二叉树
题目描述
请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。
解题思路
代码
# -*- coding:utf-8 -*-
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
class Solution:
def isSymmetrical(self, pRoot):
if not pRoot:
return True
return self.recursiveTree(pRoot.left, pRoot.right)
def recursiveTree(self, left, right):
if not left and not right:
return True
if not left or not right:
return False
if left.val == right.val:
return self.recursiveTree(left.left, right.right) and self.recursiveTree(left.right, right.left)
return False
if __name__ == '__main__':
S = Solution()
root = TreeNode(0)
node0 = TreeNode(2)
node1 = TreeNode(3)
node2 = TreeNode(4)
node3 = TreeNode(2)
node4 = TreeNode(4)
node5 = TreeNode(2)
root.left = node0
root.right = node1
node1.left = node2
node1.right = node3
node3.left = node4
node4.left = node5
print(S.isSymmetrical(root))
59 按之字形顺序打印二叉树
题目描述
请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。
解题思路
代码
# -*- coding:utf-8 -*-
#
# 请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,
# 第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
class Solution:
def Print(self, pRoot):
if not pRoot:
return []
printArr = []
flag = 0
stack = [pRoot]
while stack:
tmp = []
tmp_stack = []
for node in stack:
tmp.append(node.val)
if node.left:
tmp_stack.append(node.left)
if node.right:
tmp_stack.append(node.right)
if flag % 2 == 1:
printArr.append(tmp[::-1])
else:
printArr.append(tmp)
flag = flag + 1
stack = tmp_stack[:]
return printArr
if __name__ == '__main__':
S = Solution()
root = TreeNode(0)
node0 = TreeNode(2)
node1 = TreeNode(3)
node2 = TreeNode(4)
node3 = TreeNode(2)
node4 = TreeNode(4)
node5 = TreeNode(2)
root.left = node0
root.right = node1
node1.left = node2
node1.right = node3
node3.left = node4
node4.left = node5
print(S.Print(root))
60 把二叉树打印成多行
题目描述
从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。
解题思路
代码
# -*- coding:utf-8 -*-
# 从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
class Solution:
def Print(self, pRoot):
if not pRoot:
return []
printArr = []
stack = [pRoot]
while stack:
tmp = []
tmp_stack = []
for node in stack:
tmp.append(node.val)
if node.left:
tmp_stack.append(node.left)
if node.right:
tmp_stack.append(node.right)
printArr.append(tmp)
stack = tmp_stack[:]
return printArr
if __name__ == '__main__':
S = Solution()
root = TreeNode(0)
node0 = TreeNode(2)
node1 = TreeNode(3)
node2 = TreeNode(4)
node3 = TreeNode(2)
node4 = TreeNode(4)
node5 = TreeNode(2)
root.left = node0
root.right = node1
node1.left = node2
node1.right = node3
node3.left = node4
node4.left = node5
print(S.Print(root))
61 序列化二叉树
题目描述
请实现两个函数,分别用来序列化和反序列化二叉树
二叉树的序列化是指:把一棵二叉树按照某种遍历方式的结果以某种格式保存为字符串,从而使得内存中建立起来的二叉树可以持久保存。序列化可以基于先序、中序、后序、层序的二叉树遍历方式来进行修改,序列化的结果是一个字符串,序列化时通过 某种符号表示空节点(#),以 ! 表示一个结点值的结束(value!)。
二叉树的反序列化是指:根据某种遍历顺序得到的序列化字符串结果str,重构二叉树。
解题思路
代码
# -*- coding:utf-8 -*-
# 请实现两个函数,分别用来序列化和反序列化二叉树
# 先序遍历,root->left->right
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
class Solution:
def Serialize(self, pRoot):
serializeStr = ''
if pRoot == None:
return '#'
stack = []
while pRoot or stack:
while pRoot:
serializeStr += str(pRoot.val) + ','
stack.append(pRoot)
pRoot = pRoot.left
serializeStr += '#,'
pRoot = stack.pop()
pRoot = pRoot.right
serializeStr = serializeStr[:-1]
return serializeStr
def Deserialize(self, s):
serialize = s.split(',')
tree, sp = self.deserialize(serialize, 0)
return tree
def deserialize(self, s, sp):
if sp >= len(s) or s[sp] == '#':
return None, sp + 1
node = TreeNode(int(s[sp]))
sp += 1
node.left, sp = self.deserialize(s, sp)
node.right, sp = self.deserialize(s, sp)
return node, sp
if __name__ == '__main__':
S = Solution()
root = TreeNode(0)
node0 = TreeNode(2)
node1 = TreeNode(3)
node2 = TreeNode(4)
node3 = TreeNode(2)
node4 = TreeNode(4)
node5 = TreeNode(2)
root.left = node0
root.right = node1
node1.left = node2
node1.right = node3
node3.left = node4
node4.left = node5
ser = S.Serialize(root)
print(ser)
ser = S.Serialize(S.Deserialize(ser))
print(ser)
62 二叉搜索树的第k个结点
题目描述
给定一棵二叉搜索树,请找出其中的第k小的结点。例如, (5,3,7,2,4,6,8) 中,按结点数值大小顺序第三小结点的值为4。
解题思路
代码
# -*- coding:utf-8 -*-
# 给定一棵二叉搜索树,请找出其中的第k小的结点。
# 例如,(5,3,7,2,4,6,8)中,按结点数值大小顺序第三小结点的值为4。
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
class Solution:
def KthNode(self, pRoot, k):
stack = []
while True:
if pRoot:
stack.append(pRoot)
pRoot = pRoot.left
else:
if not stack:
return
pRoot = stack.pop()
k = k - 1
if k == 0:
return pRoot.val
else:
pRoot = pRoot.right
if __name__ == '__main__':
S = Solution()
root = TreeNode(0)
node0 = TreeNode(2)
node1 = TreeNode(3)
node2 = TreeNode(4)
node3 = TreeNode(2)
node4 = TreeNode(4)
node5 = TreeNode(2)
root.left = node0
root.right = node1
node1.left = node2
node1.right = node3
node3.left = node4
node4.left = node5
print(S.KthNode(root, 1))
63 数据流中的中位数
题目描述
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。
解题思路
代码
# -*- coding:utf-8 -*-
# 如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,
# 那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,
# 那么中位数就是所有数值排序之后中间两个数的平均值。
# 我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。
from heapq import *
class Solution:
def __init__(self):
self.left = []
self.right = []
self.count = 0
def Insert(self, num):
if self.count & 1 == 0:
self.left.append(num)
else:
self.right.append(num)
self.count += 1
def GetMedian(self, x):
if self.count == 1:
return self.left[0]
self.MaxHeap(self.left)
self.MinHeap(self.right)
if self.left[0] > self.right[0]:
self.left[0], self.right[0] = self.right[0], self.left[0]
self.MaxHeap(self.left)
self.MinHeap(self.right)
if self.count & 1 == 0:
return (self.left[0] + self.right[0]) / 2.0
else:
return self.left[0]
def MaxHeap(self, alist):
length = len(alist)
if alist == None or length <= 0:
return
if length == 1:
return alist
for i in range(length // 2 - 1, -1, -1):
k = i
temp = alist[k]
heap = False
while not heap and 2 * k < length - 1:
index = 2 * k + 1
if index < length - 1:
if alist[index] < alist[index + 1]: index += 1
if temp >= alist[index]:
heap = True
else:
alist[k] = alist[index]
k = index
alist[k] = temp
def MinHeap(self, alist):
length = len(alist)
if alist == None or length <= 0:
return
if length == 1:
return alist
for i in range(length // 2 - 1, -1, -1):
k = i
temp = alist[k]
heap = False
while not heap and 2 * k < length - 1:
index = 2 * k + 1
if index < length - 1:
if alist[index] > alist[index + 1]: index += 1
if temp <= alist[index]:
heap = True
else:
alist[k] = alist[index]
k = index
alist[k] = temp
class Solution1:
def __init__(self):
self.heaps = [], []
def Insert(self, num):
small, large = self.heaps
heappush(small, -heappushpop(large, num))
if len(large) < len(small):
heappush(large, -heappop(small))
def GetMedian(self, x):
small, large = self.heaps
if len(large) > len(small):
return float(large[0])
return (large[0] - small[0]) / 2.0
if __name__ == '__main__':
S = Solution1()
S.Insert(1)
S.Insert(2)
S.Insert(3)
S.Insert(4)
S.Insert(5)
print(S.GetMedian(1))
64 滑动窗口的最大值
题目描述
给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}; 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。
解题思路
代码
# -*- coding:utf-8 -*-
# 给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。
# 例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,
# 那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5};
# 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个:
# {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1},
# {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1},
# {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。
class Solution:
def maxInWindows(self, num, size):
if size <= 0 or len(num) <= 0:
return []
res = []
for i in range(len(num) - size + 1):
res.append(max(num[i:i + size]))
return res
def maxInWindows_deque(self, num, size):
if num == None or size <= 0:
return []
deque = []
if len(num) >= size:
index = []
for i in range(size):
while len(index) > 0 and num[i] > num[index[-1]]:
index.pop()
index.append(i)
for i in range(size, len(num)):
deque.append(num[index[0]])
while len(index) > 0 and num[i] > num[index[-1]]:
index.pop()
if len(index) > 0 and index[0] <= i - size:
index.pop(0)
index.append(i)
deque.append(num[index[0]])
return deque
if __name__ == '__main__':
S = Solution()
print(S.maxInWindows_deque([1, 2, 3, 4, 5, 6], 2))
65 矩阵中的路径
题目描述
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则该路径不能再进入该格子。 例如 a b c e s f c s a d e e 矩阵中包含一条字符串"bcced"的路径,但是矩阵中不包含"abcb"路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。
解题思路
代码
# -*- coding:utf-8 -*-
# 请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。
# 路径可以从矩阵中的任意一个格子开始,
# 每一步可以在矩阵中向左,向右,向上,向下移动一个格子。
# 如果一条路径经过了矩阵中的某一个格子,则之后不能再次进入这个格子。
# 例如 a b c e s f c s a d e e 这样的3 X 4 矩阵中包含一条字符串"bcced"的路径,
# 但是矩阵中不包含"abcb"路径,
# 因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,
# 路径不能再次进入该格子。
class Solution:
def hasPath(self, matrix, rows, cols, path):
if len(matrix) == 0 or len(matrix) != rows * cols or len(path) == 0:
return False
visited = [False] * len(matrix)
pathlength = [0]
# 以矩阵中每一个位置作为起点进行搜索
for i in range(rows):
for j in range(cols):
if self.haspath(matrix, rows, cols, path, j, i, visited, pathlength):
return True
return False
# 判断矩阵位置(x,y)的字符能否加入已找到的路径中
def haspath(self, matrix, rows, cols, path, x, y, visited, pathlength):
'''
:param matrix:字符矩阵
:param rows:矩阵的行数
:param cols:矩阵的列数
:param path:需要寻找的路径
:param x:当前位置的横坐标(对应列数)
:param y:当前位置的纵坐标(对应行数)
:param visited:访问标志数组
:param pathlength:已经找到的路径长度
:return:是否存在路径
'''
if pathlength[0] == len(path):
return True
curhaspath = False
# 参数校验:
# 1、位置坐标不超过行列数
# 2、当前位置字符等于路径中对应位置的字符
# 3、当前位置未存在于当前已找到的路径中
if 0 <= x < cols \
and 0 <= y < rows \
and matrix[y * cols + x] == path[pathlength[0]] \
and not visited[y * cols + x]:
visited[y * cols + x] = True
pathlength[0] += 1
# 分别向左,向右,向上,向下移动一个格子,任一方向能够继续往下走均可
curhaspath = self.haspath(matrix, rows, cols, path, x - 1, y, visited, pathlength) \
or self.haspath(matrix, rows, cols, path, x, y - 1, visited, pathlength) \
or self.haspath(matrix, rows, cols, path, x + 1, y, visited, pathlength) \
or self.haspath(matrix, rows, cols, path, x, y + 1, visited, pathlength)
# 如果不能再走下一步,需要回退到上一状态
if not curhaspath:
pathlength[0] -= 1
visited[y * cols + x] = False
return curhaspath
if __name__ == '__main__':
S = Solution()
print(S.hasPath(['a', 'b', 'c', 'e', 's', 'f', 'c', 's', 'a', 'd', 'e', 'e'], 3, 4, 'bcced'))
66 机器人的运动范围
题目描述
地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?
解题思路
代码
# -*- coding:utf-8 -*-
# 地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,
# 每一次只能向左,右,上,下四个方向移动一格,
# 但是不能进入行坐标和列坐标的数位之和大于k的格子。
# 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。
# 但是,它不能进入方格(35,38),因为3+5+3+8 = 19。
# 请问该机器人能够达到多少个格子?
class Solution:
def movingCount(self, threshold, rows, cols):
memories = set()
def dfs(i, j):
if not (sum(map(int, str(i) + str(j))) <= threshold) or (i, j) in memories:
return
memories.add((i, j))
if i != rows - 1:
dfs(i + 1, j)
if j != cols - 1:
dfs(i, j + 1)
dfs(0, 0)
return len(memories)
if __name__ == '__main__':
S = Solution()
print(S.movingCount(18, 40, 40))
print(str(123) + str(543))
print(list(map(int, str(123) + str(543))))
print(list(map(int, '123543')))
print(sum(map(int, str(123) + str(543))))