面试题3 二维数组中的查找 LeetCode
题目:二维数组中,每行从左到右递增,每列从上到下递增,给出一个数,判断它是否在数组中
思路:从左下角或者右上角开始比较
def find_integer(matrix, num):
"""
:param matrix: [[]]
:param num: int
:return: bool
"""
if not matrix:
return False
rows, cols = len(matrix), len(matrix[0])
row, col = rows - 1, 0
while row >= 0 and col <= cols - 1:
if matrix[row][col] == num:
return True
elif matrix[row][col] > num:
row -= 1
else:
col += 1
return False
面试题4 替换空格
题目:把字符串中的空格替换成'20%'
方法1:直接使用Python字符串的内置函数
' a b '.replace(' ', '20%')
面试题5 从尾到头打印单链表
方法1:使用栈,可以使用列表模拟
def print_links(links):
stack = []
while links:
stack.append(links.val)
links = links.next
while stack:
print stack.pop()
面试题6 重建二叉树 LeetCode
要求:用前序和中序遍历结果构建二叉树,遍历结果中不包含重复值
思路:前序的第一个元素是根结点的值,在中序中找到该值,中序中该值的左边的元素是根结点的左子树,右边是右子树,然后递归的处理左边和右边
提示:二叉树结点,以及对二叉树的各种操作,测试代码见six.py
def construct_tree(preorder=None, inorder=None):
"""
构建二叉树
"""
if not preorder or not inorder:
return None
index = inorder.index(preorder[0])
left = inorder[0:index]
right = inorder[index+1:]
root = TreeNode(preorder[0])
root.left = construct_tree(preorder[1:1+len(left)], left)
root.right = construct_tree(preorder[-len(right):], right)
return root
面试题7 用两个栈实现队列
要求:用两个栈实现队列,分别实现入队和出队操作 思路:一个栈负责入队,另一个负责出队,出栈为空则从入栈中导入到出栈中
class MyQueue(object):
def __init__(self):
self.stack = []
self.stack2 = []
def push(self, val):
self.stack.append(val)
def pop(self):
if self.stack2:
return self.stack2.pop()
while self.stack:
self.stack2.append(self.stack.pop())
return self.stack2.pop() if self.stack2 else u'队列为空'
面试题8 旋转数组的最小数字
要求:把递增数组的前面部分数字移到队尾,求数组中的最小值,例如[3,4,5,6,1,2]
思路:使用二分法,但要考虑[1, 0, 0, 1]这种数据,只能顺序查找
def find_min(nums):
if not nums:
return False
length = len(nums)
left, right = 0, length - 1
while nums[left] >= nums[right]:
if right - left == 1:
return nums[right]
mid = (left + right) / 2
if nums[left] == nums[mid] == nums[right]:
return min(nums)
if nums[left] <= nums[mid]:
left = mid
if nums[right] >= nums[mid]:
right = mid
return nums[0]
面试题9 斐波那契数列
思路:用生成器
def fib(num):
a, b = 0, 1
for i in xrange(num):
yield b
a, b = b, a + b
面试题10 二进制中1的个数
要求:求一个整数的二进制表示中,1的个数
思路:二进制表示中,最后的那个1被减去后,低位都变为0,高位不变,按位与就可以去掉这个1
def num_of_1(n):
ret = 0
while n:
ret += 1
n = n & n-1
return ret
面试题11 数值的整数次方
要求:求一个数的整数次方
思路:需要考虑次方是正数、负数和0,基数是0
浮点数相等不能直接用==
def power(base, exponent):
if equal_zero(base) and exponent < 0:
raise ZeroDivisionError
ret = power_value(base, abs(exponent))
if exponent < 0:
return 1.0 / ret
else:
return ret
def equal_zero(num):
if abs(num - 0.0) < 0.0000001:
return True
def power_value(base, exponent):
if exponent == 0:
return 1
if exponent == 1:
return base
ret = power_value(base, exponent >> 1)
ret *= ret
if exponent & 1 == 1:
ret *= base
return ret
面试题12 打印1到最大的n位数
要求:输入n,打印出从1到最大的n位数
思路:Python中已经对大整数可以进行自动转换了,所以不需要考虑大整数溢出问题
def print_max_n(n):
for i in xrange(10 ** n):
print i
面试题13 O(1)时间删除链表结点
要求:O(1)时间删除链表结点
思路:如果有后续结点,后续结点的值前移,删除后续结点,如果没有,只能顺序查找了
def delete_node(link, node):
if node == link: # 只有一个结点
del node
if node.next is None: # node是尾结点
while link:
if link.next == node:
link.next = None
link = link.next
else:
node.val = node.next.val
n_node = node.next
node.next = n_node.next
del n_node
面试题14 调整数组顺序使奇数位于偶数前面
思路:使用两个指针,前后各一个,为了更好的扩展性,可以把判断奇偶部分抽取出来
def reorder(nums, func):
left, right = 0, len(nums) - 1
while left < right:
while not func(nums[left]):
left += 1
while func(nums[right]):
right -= 1
if left < right:
nums[left], nums[right] = nums[right], nums[left]
def is_even(num):
return (num & 1) == 0
面试题15 链表中倒数第k个结点
要求:求单链表中的倒数第k个结点
思路:使用快慢指针,快的先走k-1步,需要考虑空链表以及k为0
def last_kth(link, k):
if not link or k <= 0:
return None
move = link
while move and k-1 >= 0:
move = move.next
k -= 1
while move:
move = move.next
link = link.next
if k == 0:
return link.val
return None
面试题16 反转链表
要求:反转链表
思路:需要考虑空链表,只有一个结点的链表
def reverse_link(head):
if not head or not head.next:
return head
then = head.next
head.next = None
last = then.next
while then:
then.next = head
head = then
then = last
if then:
last = then.next
return head
面试题17 合并两个排序的链表
要求:合并两个排序的链表
思路:使用递归
def merge_link(head1, head2):
if not head1:
return head2
if not head2:
return head1
if head1.val <= head2.val:
ret = head1
ret.next = merge_link(head1.next, head2)
else:
ret = head2
ret.next = merge_link(head1, head2.next)
return ret
面试题18 树的子结构
要求:判断一棵二叉树是不是另一个的子结构
思路:使用递归
def sub_tree(tree1, tree2):
if tree1 and tree2:
if tree1.val == tree2.val:
return sub_tree(tree1.left, tree2.left) and sub_tree(tree1.right, tree2.right)
else:
return sub_tree(tree1.left, tree2) or sub_tree(tree1.right, tree2)
if not tree1 and tree2:
return False
return True
面试题19 二叉树的镜像
思路一:可以按层次遍历,每一层从右到左
思路二:使用递归
def mirror_bfs(root):
ret = []
queue = deque([root])
while queue:
node = queue.popleft()
if node:
ret.append(node.val)
queue.append(node.right)
queue.append(node.left)
return ret
def mirror_pre(root):
ret = []
def traversal(root):
if root:
ret.append(root.val)
traversal(root.right)
traversal(root.left)
traversal(root)
return ret
面试题20 顺时针打印矩阵
def print_matrix(matrix):
"""
:param matrix: [[]]
"""
rows = len(matrix)
cols = len(matrix[0]) if matrix else 0
start = 0
ret = []
while start * 2 < rows and start * 2 < cols:
print_circle(matrix, start, rows, cols, ret)
start += 1
print ret
def print_circle(matrix, start, rows, cols, ret):
row = rows - start - 1 # 最后一行
col = cols - start - 1
# left->right
for c in range(start, col+1):
ret.append(matrix[start][c])
# top->bottom
if start < row:
for r in range(start+1, row+1):
ret.append(matrix[r][col])
# right->left
if start < row and start < col:
for c in range(start, col)[::-1]:
ret.append(matrix[row][c])
# bottom->top
if start < row and start < col:
for r in range(start+1, row)[::-1]:
ret.append(matrix[r][start])
面试题21 包含min函数的栈
要求:栈的push,pop,min操作的时间复杂度都是O(1)
思路:使用一个辅助栈保存最小值
class MyStack(object):
def __init__(self):
self.stack = []
self.min = []
def push(self, val):
self.stack.append(val)
if self.min and self.min[-1] < val:
self.min.append(self.min[-1])
else:
self.min.append(val)
def pop(self):
if self.stack:
self.min.pop()
return self.stack.pop()
return None
def min(self):
return self.min[-1] if self.min else None
面试题22 栈的压入弹出序列
要求:判断给定的两个序列中,后者是不是前者的弹出序列,给定栈不包含相同值
思路:使用一个辅助栈, 如果辅助栈栈顶元素不等于出栈元素,则从入栈中找改值,直到入栈为空
如果最后出栈序列为空,则是入栈的弹出序列值
def pop_order(push_stack, pop_stack):
if not push_stack or not pop_stack:
return False
stack = []
while pop_stack:
pop_val = pop_stack[0]
if stack and stack[-1] == pop_val:
stack.pop()
pop_stack.pop(0)
else:
while push_stack:
if push_stack[0] != pop_val:
stack.append(push_stack.pop(0))
else:
push_stack.pop(0)
pop_stack.pop(0)
break
if not push_stack:
while stack:
if stack.pop() != pop_stack.pop(0):
return False
if not pop_stack:
return True
return False
面试题23 从上往下打印二叉树
思路:广度优先搜索,按层次遍历
def bfs(tree):
if not tree:
return None
stack = [tree]
ret = []
while stack:
node = stack.pop(0)
ret.append(node.val)
if node.left:
stack.append(node.left)
if node.right:
stack.append(node.right)
return ret
面试题24 二叉搜索树的后序遍历序列
要求:判断给定的整数数组是不是二叉搜索树的后序遍历序列
整数数组中不包含重复值
整数序列的最后一个值是根结点,然后比根结点小的值是左子树,剩下的是右子树,递归左右子树
def is_post_order(order):
length = len(order)
if length:
root = order[-1]
left = 0
while order[left] < root:
left += 1
right = left
while right < length - 1:
if order[right] < root:
return False
right += 1
left_ret = True if left == 0 else is_post_order(order[:left])
right_ret = True if left == right else is_post_order(order[left:right])
return left_ret and right_ret
return False
面试题25 二叉树中和为某一值的路径
要求:输入一棵二叉树和一个值,求从根结点到叶结点的和等于该值的路径
深度优先搜索变形
def find_path(tree, num):
ret = []
if not tree:
return ret
path = [tree]
sums = [tree.val]
def dfs(tree):
if tree.left:
path.append(tree.left)
sums.append(sums[-1]+tree.left.val)
dfs(tree.left)
if tree.right:
path.append(tree.right)
sums.append(sums[-1] + tree.right.val)
dfs(tree.right)
if not tree.left and not tree.right:
if sums[-1] == num:
ret.append([p.val for p in path])
path.pop()
sums.pop()
dfs(tree)
return ret
面试题26 复杂链表的复制
要求:链表中除了指向后一个结点的指针之外,还有一个指针指向任意结点
分为三步完成:
一:复制每个结点,并把新结点放在老结点后面,如1->2,复制为1->1->2->2
二:为每个新结点设置other指针
三:把复制后的结点链表拆开
题目设置了复杂链表的实现,测试代码见文件twenth_six.py
class Solution(object):
@staticmethod
def clone_nodes(head):
# 结点复制
move = head
while move:
tmp = Node(move.val)
tmp.next = move.next
move.next = tmp
move = tmp.next
return head
@staticmethod
def set_nodes(head):
# other指针设置
move = head
while move:
m_next = move.next
if move.other:
m_next.other = move.other.next
move = m_next.next
return head
@staticmethod
def reconstruct_nodes(head):
# 结点拆分
ret = head.next if head else Node
move = ret
while head:
head = move.next
if head:
move.next = head.next
move = move.next
return ret
@staticmethod
def clone_link(head):
# 结果
h = Solution.clone_nodes(head)
h = Solution.set_nodes(h)
ret = Solution.reconstruct_nodes(h)
return ret
面试题27 二叉搜索树与双向链表
要求: 将二叉搜索树转化成一个排序的双向链表,只调整树中结点的指向
思路: 中序遍历,根结点的left指向左子树的最后一个(最大)值,right指向右子树的(最小)值
注意: 题目构造了一个普通二叉树用来测试,构造时按照二叉搜索树的顺序输入结点,空结点用None表示,详情见twenty_seven.py
class Solution(object):
@staticmethod
def convert(tree):
"""结点转换"""
if not tree:
return None
p_last = Solution.convert_nodes(tree, None)
while p_last and p_last.left: # 获取链表头结点
p_last = p_last.left
return p_last
@staticmethod
def convert_nodes(tree, last):
if not tree:
return None
if tree.left:
last = Solution.convert_nodes(tree.left, last)
if last:
last.right = tree
tree.left = last
last = tree
if tree.right:
last = Solution.convert_nodes(tree.right, last)
return last
面试题28 字符串的排列
要求:求输入字符串的全排列
思路:递归完成,也可以直接使用库函数
def my_permutation(s):
str_set = []
ret = [] # 最后的结果
def permutation(string):
for i in string:
str_tem = string.replace(i, '')
str_set.append(i)
if len(str_tem) > 0:
permutation(str_tem)
else:
ret.append(''.join(str_set))
str_set.pop()
permutation(s)
return ret
面试题29 数组中出现次数超过一半的数字
思路: 使用hash,key是数字,value是出现的次数
注意: 列表的len方法的时间复杂度是O(1)
def get_more_half_num(nums):
hashes = dict()
length = len(nums)
for n in nums:
hashes[n] = hashes[n] + 1 if hashes.get(n) else 1
if hashes[n] > length / 2:
return n
面试题30 最小的k个数
要求:求数组中出现次数超过一半的数字
思路: 使用heapq,该模块是一个最小堆,需要转化成最大堆,只要在入堆的时候把值取反就可以转化成最大堆(仅适用于数字)
思路二: 数组比较小的时候可以直接使用heapq的nsmallest方法
import heapq
def get_least_k_nums(nums, k):
# 数组比较小的时候可以直接使用
return heapq.nsmallest(k, nums)
class MaxHeap(object):
def __init__(self, k):
self.k = k
self.data = []
def push(self, elem):
elem = -elem # 入堆的时候取反,堆顶就是最大值的相反数了
if len(self.data) < self.k:
heapq.heappush(self.data, elem)
else:
least = self.data[0]
if elem > least:
heapq.heapreplace(self.data, elem)
def get_least_k_nums(self):
return sorted([-x for x in self.data])
面试题31 连续子数组的最大和
思路: 动态规划问题
def max_sum(nums):
ret = float("-inf") # 负无穷
if not nums:
return ret
current = 0
for i in nums:
if current <= 0:
current = i
else:
current += i
ret = max(ret, current)
return ret
面试题32 从1到n整数中1出现的次数
要求:求从1到n整数的十进制表示中,1出现的次数
思路: 获取每个位数区间上所有数中包含1的个数,然后分别对高位分析,然后递归的处理低位数
此题中,作者的描述我没有理解,按照自己的理解写了一下,具体内容请点击这里
def get_digits(n):
# 求整数n的位数
ret = 0
while n:
ret += 1
n /= 10
return ret
def get_1_digits(n):
"""
获取每个位数之间1的总数
:param n: 位数
"""
if n <= 0:
return 0
if n == 1:
return 1
current = 9 * get_1_digits(n-1) + 10 ** (n-1)
return get_1_digits(n-1) + current
def get_1_nums(n):
if n < 10:
return 1 if n >= 1 else 0
digit = get_digits(n) # 位数
low_nums = get_1_digits(digit-1) # 最高位之前的1的个数
high = int(str(n)[0]) # 最高位
low = n - high * 10 ** (digit-1) # 低位
if high == 1:
high_nums = low + 1 # 最高位上1的个数
all_nums = high_nums
else:
high_nums = 10 ** (digit - 1)
all_nums = high_nums + low_nums * (high - 1) # 最高位大于1的话,统计每个多位数后面包含的1
return low_nums + all_nums + get_1_nums(low)
面试题33 把数组排成最小的数
要求:把数组中的值拼接,找出能产生的最小的数[321,32,3]最小的数是321323
思路: Python中不需要考虑大整数,需要自己定义一个数组排序规则,直接调用库函数就可以
def cmp(a, b):
return int(str(a)+str(b)) - int(str(b)+str(a))
def print_mini(nums):
print int(''.join([str(num) for num in sorted(nums, cmp=cmp)]))
面试题34 丑数 LeetCode
要求:只含有2、3、5因子的数是丑数,求第1500个丑数
思路: 按顺序保存已知的丑数,下一个是已知丑数中某三个数乘以2,3,5中的最小值
class Solution(object):
def nthUglyNumber(self, n):
"""
:type n: int
:rtype: int
"""
ugly = [1]
t2 = t3 = t5 = 0
while len(ugly) < n:
while ugly[t2] * 2 <= ugly[-1]:
t2 += 1
while ugly[t3] * 3 <= ugly[-1]:
t3 += 1
while ugly[t5] * 5 <= ugly[-1]:
t5 += 1
ugly.append(min(ugly[t2]*2, ugly[t3]*3, ugly[t5]*5))
return ugly[-1]
面试题35 第一个只出现一次的字符
要求:求字符串中第一个只出现一次的字符
思路: 使用两个hash,一个记录每个字符穿线的次数,另一个记录每个字符第一次出现的位置
def first_not_repeating_char(string):
if not string:
return -1
count = {}
loc = {}
for k, s in enumerate(string):
count[s] = count[s] + 1 if count.get(s) else 1
loc[s] = loc[s] if loc.get(s) else k
ret = float('inf')
for k in loc.keys():
if count.get(k) == 1 and loc[k] < ret:
ret = loc[k]
return ret
面试题36 数组中的逆序对
要求:在一个数组中,前面的数字比后面的大,就是一个逆序对,求总数
思路: 归并排序,先把数组依次拆开,然后合并的时候统计逆序对数目,并排序
import copy
def get_inverse_pairs(nums):
if not nums:
return 0
start, end = 0, len(nums) - 1
tmp = copy.deepcopy(nums)
return inverse_pairs(tmp, start, end)
def inverse_pairs(tmp, start, end):
if start == end: # 递归结束条件
return 0
mid = (end - start) / 2 # 分别对左右两边递归求值
left = inverse_pairs(tmp, start, start+mid)
right = inverse_pairs(tmp, start+mid+1, end)
count = 0 # 本次逆序对数目
l_right, r_right = start + mid, end
t = []
while l_right >= start and r_right >= start + mid + 1:
if tmp[l_right] > tmp[r_right]:
t.append(tmp[l_right])
count += (r_right - mid - start)
l_right -= 1
else:
t.append(tmp[r_right])
r_right -= 1
while l_right >= start:
t.append(tmp[l_right])
l_right -= 1
while r_right >= start+mid+1:
t.append(tmp[r_right])
r_right -= 1
tmp[start:end+1] = t[::-1]
return count + left + right
面试题37 两个链表的第一个公共结点
思路: 先获取到两个链表的长度,然后长的链表先走多的几步,之后一起遍历
文件thirty_seven.py中包含了设置链表公共结点的代码,可以用来测试
def get_first_common_node(link1, link2):
if not link1 or not link2:
return None
length1 = length2 = 0
move1, move2 = link1, link2
while move1: # 获取链表长度
length1 += 1
move1 = move1.next
while move2:
length2 += 1
move2 = move2.next
while length1 > length2: # 长链表先走多的长度
length1 -= 1
link1 = link1.next
while length2 > length1:
length2 -= 1
link2 = link2.next
while link1: # 链表一起走
if link1 == link2:
return link1
link1, link2 = link1.next, link2.next
return None
面试题38 数字在排序数组中出现的次数
思路: 使用二分法分别找到数组中第一个和最后一个出现的值的坐标,然后相减
def get_k_counts(nums, k):
first = get_first_k(nums, k)
last = get_last_k(nums, k)
if first < 0 and last < 0:
return 0
if first < 0 or last < 0:
return 1
return last - first + 1
def get_first_k(nums, k):
left, right = 0, len(nums) - 1
while left <= right:
mid = (left + right) / 2
if nums[mid] < k:
if mid + 1 < len(nums) and nums[mid+1] == k:
return mid + 1
left = mid + 1
elif nums[mid] == k:
if mid - 1 < 0 or (mid - 1 >= 0 and nums[mid-1] < k):
return mid
right = mid - 1
else:
right = mid - 1
return -1
def get_last_k(nums, k):
left, right = 0, len(nums) - 1
while left <= right:
mid = (left + right) / 2
if nums[mid] < k:
left = mid + 1
elif nums[mid] == k:
if mid + 1 == len(nums) or (mid + 1 < len(nums) and nums[mid+1] > k):
return mid
left = mid + 1
else:
if mid - 1 >= 0 and nums[mid-1] == k:
return mid - 1
right = mid - 1
return -1
面试题39 二叉树的深度
思路: 分别递归的求左右子树的深度
def get_depth(tree):
if not tree:
return 0
if not tree.left and not tree.right:
return 1
return 1 + max(get_depth(tree.left), get_depth(tree.right))
面试题40 数组中只出现一次的数字
要求:数组中除了两个只出现一次的数字外,其他数字都出现了两遍
思路: 按位异或,在得到的值中找到二进制最后一个1,然后把数组按照该位是0还是1分为两组
def get_only_one_number(nums):
if not nums:
return None
tmp_ret = 0
for n in nums: # 获取两个值的异或结果
tmp_ret ^= n
last_one = get_bin(tmp_ret)
a_ret, b_ret = 0, 0
for n in nums:
if is_one(n, last_one):
a_ret ^= n
else:
b_ret ^= n
return [a_ret, b_ret]
def get_bin(num): # 得到第一个1
ret = 0
while num & 1 == 0 and ret < 32:
num = num >> 1
ret += 1
return ret
def is_one(num, t): # 验证t位是不是1
num = num >> t
return num & 0x01
面试题41 和为s的两个数字VS和为s的连续正数序列
和为s的两个数字
要求:输入一个递增排序的数组和一个数字s,在数组中查找两个数,使其和为s
思路: 设置头尾两个指针,和大于s,尾指针减小,否砸头指针增加
def sum_to_s(nums, s):
head, end = 0, len(nums) - 1
while head < end:
if nums[head] + nums[end] == s:
return [nums[head], nums[end]]
elif nums[head] + nums[end] > s:
end -= 1
else:
head += 1
return None
和为s的连续整数序列
要求:输入一个正数s, 打印出所有和为s的正整数序列(至少两个数)
思路: 使用两个指针,和比s小,大指针后移,比s大,小指针后移
def sum_to_s(s):
a, b = 1, 2
ret = []
while a < s / 2 + 1:
if sum(range(a, b+1)) == s:
ret.append(range(a, b+1))
a += 1
elif sum(range(a, b+1)) < s:
b += 1
else:
a += 1
return ret
面试题42 翻转单词顺序与左旋转字符串
翻转单词顺序
要求:翻转一个英文句子中的单词顺序,标点和普通字符一样处理
思路: Python中字符串是不可变对象,不能用书中的方法,可以直接转化成列表然后转回去
def reverse_words(sentence):
tmp = sentence.split()
return ' '.join(tmp[::-1]) # 使用join效率更好,+每次都会创建新的字符串
左旋转字符串
思路: 把字符串的前面的若干位移到字符串的后面
def rotate_string(s, n):
if not s:
return ''
n %= len(s)
return s[n:] + s[:n]
面试题43 n个骰子的点数
要求:求出n个骰子朝上一面之和s所有可能值出现的概率
思路:n出现的可能是前面n-1到n-6出现可能的和,设置两个数组,分别保存每一轮
def get_probability(n):
if n < 1:
return []
data1 = [0] + [1] * 6 + [0] * 6 * (n - 1)
data2 = [0] + [0] * 6 * n # 开头多一个0,方便按照习惯从1计数
flag = 0
for v in range(2, n+1): # 控制次数
if flag:
for k in range(v, 6*v+1):
data1[k] = sum([data2[k-j] for j in range(1, 7) if k > j])
flag = 0
else:
for k in range(v, 6*v+1):
data2[k] = sum([data1[k-j] for j in range(1, 7) if k > j])
flag = 1
ret = []
total = 6 ** n
data = data2[n:] if flag else data1[n:]
for v in data:
ret.append(v*1.0/total)
print data
return ret
面试题44 扑克牌的顺子
要求:从扑克牌中随机抽取5张牌,判断是不是顺子,大小王可以当任意值
思路: 使用排序
import random
def is_continus(nums, k):
data = [random.choice(nums) for _ in range(k)]
data.sort()
print data
zero = data.count(0)
small, big = zero, zero + 1
while big < k:
if data[small] == data[big]:
return False
tmp = data[big] - data[small]
if tmp > 1:
if tmp - 1 > zero:
return False
else:
zero -= tmp - 1
small += 1
big += 1
else:
small += 1
big += 1
return True
面试题45 圆圈中最后剩下的数字
要求:0到n-1排成一圈,从0开始每次数m个数删除,求最后剩余的数
思路:当 n > 1 时: f(n,m) = [f(n-1, m)+m]%n,当 n = 1 时: f(n,m)=0,关键是推导出关系表达式
def last_num(n, m):
ret = 0
if n == 1:
return 0
for i in range(2, n+1):
ret = (m + ret) % i
return ret
面试题46 求1+2...+n
要求:不能使用乘除、for、while、if、else等
方法一:使用range和sum
方法二:使用reduce
def get_sum1(n):
return sum(range(1, n+1))
def get_sum2(n):
return reduce(lambda x, y: x+y, range(1, n+1))
面试题47 不用加减乘除做加法
要求:不用加减乘除做加法
方法一:使用位运算,Python中大整数会自动处理,因此对carry需要加个判断
方法二:使用sum
def bit_add(n1, n2):
carry = 1
while carry:
s = n1 ^ n2
carry = 0xFFFFFFFF & ((n1 & n2) << 1)
carry = -(~(carry - 1) & 0xFFFFFFFF) if carry > 0x7FFFFFFF else carry
n1 = s
n2 = carry
return n1
def add(n1, n2):
return sum([n1, n2])
面试题48 不能被继承的类
Python中不知道怎么实现不能被继承的类。以后补充代码或者原因。
面试题49 把字符串转化成整数
要求:把字符串转化成整数
测试用例:正负数和0,空字符,包含其他字符
备注:使用raise抛出异常作为非法提示
def str_to_int(string):
if not string: # 空字符返回异常
raise Exception('string cannot be None', string)
flag = 0 # 用来表示第一个字符是否为+、-
ret = 0 # 结果
for k, s in enumerate(string):
if s.isdigit(): # 数字直接运算
val = ord(s) - ord('0')
ret = ret * 10 + val
else:
if not flag:
if s == '+' and k == 0: # 避免中间出现+、-
flag = 1
elif s == '-' and k == 0:
flag = -1
else:
raise Exception('digit is need', string)
else:
raise Exception('digit is need', string)
if flag and len(string) == 1: # 判断是不是只有+、-
raise Exception('digit is need', string)
return ret if flag >= 0 else -ret
面试题50 树中两个结点的最低公共祖先
要求:求普通二叉树中两个结点的最低公共祖先
方法一:先求出两个结点到根结点的路径,然后从路径中找出最后一个公共结点
备注:文件fifty.py中包含该代码的具体测试数据
class Solution(object):
def __init__(self, root, node1, node2):
self.root = root # 树的根结点
self.node1 = node1
self.node2 = node2 # 需要求的两个结点
@staticmethod
def get_path(root, node, ret):
"""获取结点的路径"""
if not root or not node:
return False
ret.append(root)
if root == node:
return True
left = Solution.get_path(root.left, node, ret)
right = Solution.get_path(root.right, node, ret)
if left or right:
return True
ret.pop()
def get_last_common_node(self):
"""获取公共结点"""
route1 = []
route2 = [] # 保存结点路径
ret1 = Solution.get_path(self.root, self.node1, route1)
ret2 = Solution.get_path(self.root, self.node2, route2)
ret = None
if ret1 and ret2: # 路径比较
length = len(route1) if len(route1) <= len(route2) else len(route2)
index = 0
while index < length:
if route1[index] == route2[index]:
ret = route1[index]
index += 1
return ret
' a b '.replace(' ', '20%')
来源:https://www.cnblogs.com/qiu-hua/p/12238547.html