字符串的排列
- 问题描述: 输入一个字符串,返回字符串中字符的字典序排列
- 解题思路:每次固定一个字符,递归增加后续字符,性能最差。采用交换替代直接遍历增加,最后仍需去重。考虑需要字典序的排列,也可以用字典排序算法。
class Solution:
def Permutation(self, charseq):
if not charseq:
return []
result = set()
maxn = len(charseq)
def recur(i,cur):
if i >= maxn:
result.add(''.join(cur))
else:
for j in range(i,maxn):
if i!=j and cur[i]==cur[j]:
continue
cur[i],cur[j] = cur[j],cur[i]
recur(i+1,cur)
cur[i], cur[j] = cur[j], cur[i]
recur(0,list(charseq))
return list(sorted(result))
class Solution:
def Permutation(self, charseq):
if not charseq:
return []
charseq = sorted(list(charseq))
result = list()
result.append(''.join(charseq))
maxn = len(charseq)
i = maxn - 1
while True:
while i and charseq[i] <= charseq[i-1]:
i -= 1
if not i: break
j = maxn-1
while j > i and charseq[j] <= charseq[i-1]:
j -= 1
charseq[i-1],charseq[j] = charseq[j],charseq[i-1]
charseq[i:] = reversed(charseq[i:])
result.append(''.join(charseq))
i = maxn - 1
return result
变态跳台阶
- 问题描述:跳台阶的升级版,青蛙可以跳任意正数<=n的步数
- 解题思路:递推,为了支持跳n步,增加dp[0]=1即可
class Solution:
def __init__(self):
self.__dp = list()
self.__n = 50
for i in range(self.__n):
if i < 1:
self.__dp.append(1)
else:
fib_sum = 0
for j in range(i-1,-1,-1):
fib_sum += self.__dp[j]
self.__dp.append(fib_sum)
def jumpFloorII(self, number):
if number > self.__n:
for i in range(self.__n,number):
fib_sum = 0
for j in range(i-1,-1,-1):
fib_sum += self.__dp[j]
self.__dp.append(fib_sum)
self.__n = number
return self.__dp[number]
二进制中1的个数
- 问题描述: 补码表示的数的1的个数
- 解题思路:无fa可说
class Solution:
def NumberOf1(self, n):
n = n&0xffffffff
cnt = 0
while n:
if n&1:
cnt += 1
n >>= 1
return cnt
调整数组顺序使奇数位于偶数前面
- 问题描述:如题以外,保证奇数、偶数各自的相对位置不变
- 解题思路: 无fa可说
class Solution:
def reOrderArray(self, array):
i = 0
maxn = len(array)
while True:
while i < maxn and array[i]&1:
i += 1
if i == maxn:
break
j = i
while j < maxn and not array[j]&1:
j += 1
if j == maxn:
break
k = j
while k < maxn and array[k]&1:
k += 1
array[k-j+i:k],array[i:i+k-j] = array[i:j],array[j:k]
i += k-j
return array
数值的整数次方
- 问题描述: 求double类型浮点数的整型幂
- 解题思路:注意负指数情形
class Solution:
def Power(self, base, exponent):
result = 1
if exponent < 0:
base = 1/base
exponent *= -1
while exponent:
if exponent&1:
result *= base
exponent -= 1
else:
base = base**2
exponent >>= 1
return result
二叉树的镜像
- 问题描述: 输入一个二叉树根节点,返回其镜像二叉树的根节点
- 解题思路: 无fa可说
class Solution:
def Mirror(self, root):
if not root:
return None
if not root.left and not root.right:
return root
root.left,root.right = self.Mirror(root.right),self.Mirror(root.left)
return root
合并两个排序的链表
- 问题描述: 输入两个单调递增单链表的头节点,返回合并后单调不减的单链表的头结点
- 解题思路: 类似的题以后只考虑写起来最快的递归
class Solution:
def Merge(self, pHead1, pHead2):
if not pHead1:
return pHead2
if not pHead2:
return pHead1
if pHead1.val < pHead2.val:
pHead1.next = self.Merge(pHead1.next,pHead2)
return pHead1
else:
pHead2.next = self.Merge(pHead1,pHead2.next)
return pHead2
顺时针打印矩阵
- 问题描述:输入一个二维矩阵,返回一个从外到内、顺时针方向遍历该矩阵的一维数组
- 解题思路:与Codewars的Snail一致,这里使用矩阵旋转、递归只需要一行代码
class Solution:
def printMatrix(self, matrix):
return list(matrix[0]) + self.printMatrix(zip(*matrix[1:])[::-1]) if matrix else []
树的子结构
- 问题描述: 输入A、B两树的根节点,返回是否B树为A树的子结构,前提:空树不为任意树的子结构
- 解题思路:贪心的递归用于判断从根节点开始的子结构,主调用的递归用于搜索根节点
class Solution:
def HasSubtree(self, pRoot1, pRoot2):
def subtree_from_root(a,b):
if not b:
return True
if not a:
return False
if a.val == b.val:
return subtree_from_root(a.left,b.left) and subtree_from_root(a.right,b.right)
if not pRoot2 or not pRoot1:
return False
if subtree_from_root(pRoot1,pRoot2):
return True
else:
return self.HasSubtree(pRoot1.left,pRoot2) or self.HasSubtree(pRoot1.right,pRoot2)
栈的压入、弹出序列
- 问题描述:输入为入栈出栈的序列,返回两个序列是否合法
- 解题思路:栈混洗
class Solution:
def IsPopOrder(self, pushV, popV):
stack = list()
i,j = 0,0
maxm = len(pushV)
maxn = len(popV)
while i < maxm and j < maxn:
if stack and stack[-1]==popV[j]:
j += 1
stack.pop()
else:
stack.append(pushV[i])
i += 1
while j < maxn:
if stack and stack[-1]==popV[j]:
stack.pop()
j += 1
return not stack
从上向下打印二叉树
- 问题描述:输入二叉树根节点,返回其层序遍历的结果
- 解题思路:二叉树的层序遍历
class Solution:
def PrintFromTopToBottom(self, root):
if not root:
return []
queue = list()
queue.append(root)
result = list()
while queue:
node = queue.pop(0)
result.append(node.val)
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
return result
二叉搜索树的后序遍历序列
- 问题描述:输入一维数组,返回是否该数组为二叉搜索树的后序遍历序列,前提:一维数组中没有重复的值
- 解题思路:后序遍历产生的序列为左子树->右子树->根节点,二叉搜索树的性质使得该序列进一步具有约束:比根节点小的区段->比根节点大的区段->根节点,递归检查这一约束即可。
class Solution:
def VerifySquenceOfBST(self, sequence):
if not sequence:
return []
def recur(seq):
maxn = len(seq)
if maxn <= 2:
return True
i = maxn - 2
root = seq[-1]
while i>=0 and seq[i] > root:
i -= 1
if i == -1:
return recur(seq[:-1])
j = i
while j>=0 and seq[j] < root:
j -= 1
if j != -1:
return False
return recur(seq[i:-1]) and recur(seq[:i])
return recur(sequence)
二叉树和为某一值的路径
- 问题描述: 输入二叉树根节点和期望整数值,返回包含直到叶节点节点值加和为期望整数值的所有路径的二维数组。
- 解题思路: 无fa可说
class Solution:
def FindPath(self, root, expectNumber):
result = list()
def recur(node,num,arr):
arr.append(node.val)
num -= node.val
if not node.left and not node.right and num == 0:
result.append(arr)
if node.left:
recur(node.left,num,arr[:])
if node.right:
recur(node.right,num,arr[:])
if not root:
return []
recur(root,expectNumber,list())
return result
复杂链表的复制
- 问题描述: 输入一个复杂链表(label,random,next)的头节点,返回其复制链表的头节点。
- 解题思路: 三种思路,直接复制-暴力搜索,新旧节点映射-辅助复制random域,利用next域-新节点链接到旧节点。
class Solution:
def Clone(self, pHead):
if not pHead:
return None
tp = pHead
while tp:
ctp = RandomListNode(tp.label)
ctp.random = tp.random
ctp.next = tp.next
tp.next = ctp
tp = ctp.next
ctp = pHead
while ctp:
ctp = ctp.next
if ctp.random:
ctp.random = ctp.random.next
ctp = ctp.next
ctp = pHead.next
tp = pHead
chead = pHead.next
while ctp:
if ctp.next:
tp.next = ctp.next
ctp.next = ctp.next.next
else:
tp.next = None
ctp = ctp.next
tp = tp.next
return chead
二维数组中的查找
- 问题描述: 输入一个二维数组和一个整数,返回二维数组中是否含有该整数。前提:二维数组每个维度长度一致,按行列分别递增。
- 解题思路:从副对角线开始能规避多余的判断。
class Solution:
def Find(self, target, array):
if not array or len(array)==1 and not array[0]:
return False
maxn = len(array)
i,j=0,maxn-1
while i < maxn and j >= 0:
if array[i][j] == target:
return True
if array[i][j] > target:
j -= 1
else:
i += 1
return False
空格替换
- 问题描述: 输入一个字符串,返回其空格被替换为‘%20’后的字符串
- 解题思路: 不使用str.replace(),而是先统计空格个数,然后从后向前移位替换空格,模拟需要自己管理内存的字符串带来的粒度更细的操作。
class Solution:
def replaceSpace(self, s):
cnt = 0
for ch in s:
if ch == ' ':
cnt += 1
replaced = list(s) + ['#','#']*cnt
for i in range(len(s)-1,-1,-1):
if replaced[i] != ' ':
replaced[i+cnt*2] = replaced[i]
else:
cnt -= 1
replaced[i+cnt*2:i+cnt*2+3] = list('%20')
return ''.join(replaced)
从尾到头打印链表
- 问题描述:输入单链表的头节点,返回其从尾到头的节点值数组
- 解题思路:无fa可说
class Solution:
def printListFromTailToHead(self, listNode):
result = list()
while listNode:
result.append(listNode.val)
listNode = listNode.next
return result[::-1]
重建二叉树
- 问题描述:输入二叉树的前序遍历和中序遍历序列,返回根据两个序列建立的二叉树的头节点
- 解题思路:无fa可说
class Solution:
def reConstructBinaryTree(self, pre, tin):
def make_tree(pre_start,pre_end,tin_start,tin_end):
if pre_end <= pre_start or tin_end <= tin_start:
return None
root_val = pre[pre_start]
root = TreeNode(root_val)
pre_start += 1
for i in range(tin_start,tin_end):
if tin[i] == root_val:
root.left = make_tree(pre_start,pre_start+i-tin_start,tin_start,i)
root.right = make_tree(pre_start+i-tin_start,pre_end,i+1,tin_end)
break
return root
return make_tree(0,len(pre),0,len(tin))
用两个栈实现队列
- 问题描述: 完成Queue class的pop和push方法,采用stack实现
- 解题思路: 无fa可说
class Solution:
def __init__(self):
self.__stack = list()
self.__buf = list()
def push(self, node):
self.__stack.append(node)
def pop(self):
if not self.__buf:
while self.__stack:
self.__buf.append(self.__stack.pop())
return self.__buf.pop()
旋转数组的最小值
- 问题描述: 数组的旋转指 数组最前面的一段移到数组尾部,输入一个单调不减数组的旋转,求其最小值
- 解题思路:注意元素全等的情形。
class Solution:
def minNumberInRotateArray(self, rotateArray):
if not rotateArray:
return 0
i = 0
maxn = len(rotateArray)
while i < maxn:
if i and rotateArray[i]<rotateArray[i-1]:
return rotateArray[i]
i += 1
return rotateArray[0]
链表中倒数第k个节点
- 问题描述:输入单链表头节点和k,返回单链表中倒数第k个节点的引用
* 解题思路:注意k只能从1开始
class Solution:
def FindKthToTail(self, head, k):
arr = list()
while head:
arr.append(head)
head=head.next
if k > len(arr) or k <=0:
return None
return arr[-k]
二叉搜索树转换到双向链表
- 问题描述: 输入二叉搜索树根节点,返回双向链表头节点,要求不能新建节点,在原节点上使用left和right指针域操作
- 解题思路:在二叉树中序遍历时重设left,right
class Solution:
def Convert(self, pRootOfTree):
stack = list()
last_node = None
link_head = None
while stack or pRootOfTree:
while pRootOfTree:
stack.append(pRootOfTree)
pRootOfTree = pRootOfTree.left
pRootOfTree = stack.pop()
if not link_head:
link_head = pRootOfTree
if last_node:
pRootOfTree.left = last_node
last_node.right = pRootOfTree
last_node = pRootOfTree
pRootOfTree = pRootOfTree.right
return link_head
数组中出现次数超过一半的数字
- 问题描述: 输入一个一维数组,返回其中中出现次数超过其数组一半的数字,否则返回0
- 解题思路:用空间换时间可以几行代码搞定。超过数组一半长度,意味着所求数字如果存在,则一定为该数组的中位数,其出现次数也必然大于剩下所有数字出现次数之和。有两种不需要额外空间的办法:均采用两次O(n)的统计,第一次找该到满足其中一个条件的数,第二次判别验证。
class Solution:
def MoreThanHalfNum_Solution(self, numbers):
cnt = dict()
maxn = len(numbers)/2.0
for i in numbers:
if not i in cnt:
cnt[i] = 1
else:
cnt[i] += 1
if cnt[i] > maxn:
return i
return 0
最小的k个数
- 问题描述: 输入一个数组和整数k,返回数组中最小的k个数(单调不减)
- 解题思路:数据结构实验时为了统计topk,考虑用最小堆添加约束,这道题也是类似的,可以用最大堆,限制每次更新最大堆时做两个检查:目前的堆容量是否为k,否则加入;堆顶是否大于待添加的值,是则替掉堆顶并向下更新。但是为了快速实现,这里采用求数组中第k大数的O(n)策略,据此得到最小的k个数的无序数组。
def partition(arr,s,e):
if e - s <= 1:
return s
i = s + 1
j = e - 1
pivot = arr[s]
while i < j:
while i < j and arr[i] < pivot: i += 1
while i < j and arr[j] >= pivot: j -= 1
if i < j: arr[i],arr[j] = arr[j],arr[i]
arr[i-1],arr[s] = pivot,arr[i-1]
return i-1
class Solution:
def GetLeastNumbers_Solution(self, tinput, k):
if not tinput:
return []
maxn = len(tinput)
if maxn < k:
return []
start,end = 0,maxn
i = partition(tinput,start,end)
while i != k:
if i < k:
start = i + 1
else:
end = i
i = partition(tinput,start,end)
return sorted(tinput[:k])