劍指offer(Python實現)
- 劍指offer(Python實現)
- 面試題:實現Singleton模式
- 面試題:二維數組查找
- 面試題:替換空格
- 面試題:反向打印鏈表
- 面試題:重建二叉樹
- 面試題:用兩個棧實現隊列
- 面試題:旋轉數組的最小數字
- 面試題:斐波那契數列
- 面試題:二進制中1的個數
- 面試題:數值的整數次方
- 面試題:打印1到最大的n位數
- 面試題:在O(1)時間內刪除鏈表節點
- 面試題:調整數組順序使奇數位於偶數前面
- 面試題:鏈表中倒數第K個節點
- 面試題:反轉鏈表
- 面試題:合併兩個排序鏈表
- 面試題:樹的子結構
- 面試題:二叉樹的鏡像
- 面試題:順時針打印矩陣
- 面試題:包含min函數的棧
- 面試題:棧的壓入,彈出序列
- 面試題:從上往下打印二叉樹
- 面試題:二叉搜索樹的後續遍歷序列
- 面試題:二叉樹中和爲某一值的路徑
- 面試題:複雜鏈表的複製
- 面試題:二叉搜索樹與雙向鏈表
- 面試題:字符串的排列和組合
- 面試題:數組中出現次數超過一半的數字
- 面試題:最小的k個數
- 面試題:連續子數組的最大和
- 面試題:整數中1出現的次數(從1到n整數中1出現的次數)
- 面試題:把數組排成最小的數
- 面試題:醜數
- 面試題:第一個只出現一次的字符
- 面試題:數組中的逆序對
- 面試題:兩個鏈表的第一個公共結點
- 面試題:數字在排序數組中出現的次數
- 面試題:二叉樹的深度
- 面試題:判斷平衡二叉樹
- 面試題:數組中只出現一次的數字
- 面試題:和爲S的連續正數序列
- 面試題:和爲s的兩個數字
- 面試題:左旋轉字符串
- 面試題:反轉單詞順序列
- 面試題:撲克牌順子
- 面試題:圓圈中最後剩下的數
- 面試題:求1+2+3+...+n
- 面試題:不用加減乘除做加法
- 面試題:把字符串轉換成整數
- 面試題:數組中重複的數字
- 面試題:構建乘積矩陣
- 面試題:正則表達式匹配
- 面試題:表示數值的字符串
- 面試題:字符流中第一個不重複的字符
- 面試題:鏈表中環的入口結點
- 面試題:刪除鏈表中重複的結點
- 面試題:二叉樹的下一個結點
- 面試題:對稱的二叉樹
- 面試題:把二叉樹打印成多行
- 面試題:按之字形順序打印二叉樹
- 面試題:序列化二叉樹
- 面試題:二叉搜索樹的第k個結點
- 面試題:
- 面試題:滑動窗口的最大值
- 面試題:矩陣中的路徑
- 面試題:機器人的運動範圍
- 面試題:剪繩子
劍指offer(Python實現)
面試題:實現Singleton模式
**單例模式,**核心結構中只包含一個被稱爲單例類的特殊類,類的對象只能存在一個
三個要點: 某個類只有一個實例; 必須自行創建這個實例; 必須自行向整個系統提供這個實例
'''
單例模式,核心結構中只包含一個被稱爲單例類的特殊類,類的對象只能存在一個
三個要點: 某個類只有一個實例; 必須自行創建這個實例; 必須自行向整個系統提供這個實例
'''
"""
方法1:實現__new__方法,然後將類的一個實例綁定到類變量_instance上
如果cls._instance爲None,說明該類沒有被實例化過,new一個該類的實例,並返回
如果cls._instance不是None,直接返回——instance
"""
class Singleton1(object):
def __new__(cls,*args,**kwargs):
if not hasattr(cls,'_instance'):
orig = super(Singleton1,cls)
cls._instance = orig.__new__(cls,*args,**kwargs)
return cls._instance
class Myclass(Singleton1):
a = 1
one = Myclass()
two = Myclass()
# one和two完全相同,可以用id(),==,is檢測
print(id(one))
print(id(two))
print(one == two) #True
print(one is two) #True
two.a = 3
print(one.a) # 3
"""
方法2:共享屬性:所謂單例就是所有引用(實例、對象)擁有相同的狀態(屬性)和行爲(方法)
同一個類的所有實例天然有相同的行爲(方法)
只需要保證一個類的所有實例具有相同的狀態(屬性)即可
所有實例共享屬性的最簡單方法就是__dict__屬性指向(引用)同一個字典(dict)
"""
class Borg(object):
_state = {}
def __new__(cls, *args, **kwargs):
ob = super(Borg, self).__new__(cls,*args,**kwargs)
ob.__dict__ = cls._state
return ob
class MyClass2(Borg):
a = 1
one = MyClass2()
two = MyClass2()
two.a = 3
print(one.a)
# one 和 two 是兩個不同的對象,id,==,is對比結果可以看出
print(id(one)) # 18410480
print(id(two)) # 18410512
print(one == two) # False
print(one is two) # False
# 但是one和two具有相同的(同一個)__dict__屬性
print(id(one.__dict__)) # 14194768
print(id(two.__dict__)) # 14194768
"""
方法3:裝飾器版本decorator
這是一種更pythonic,更elegant的方法
單例類本身根本不知道自己是單例的,因爲他自己的代碼不是單例的
"""
def singleton(cls,*args,**kwargs):
instances = {}
def getinstance():
if cls not in instances:
instances[cls] = cls(*args,**kwargs)
return instances[cls]
return getinstance
@singleton
class MyClass3(object):
a = 1
def __init__(self,x = 0):
self.x = x
one = MyClass3()
two = MyClass3()
two.a = 3
print(one.a) # 3
print(id(one)) # 8842576
print(id(two)) # 8842576
print(one == two) # True
print(one is two) # True
one.x = 1
print(one.x) # 1
print(two.x) # 1
'''
方法4:import方法
python中的模塊module在程序中只被加載一次,本身就是單例的
可以直接寫一個模塊,將你需要的方法和屬性,寫在模塊中當做函數和模塊作用域的全局變量即可,根本不需要寫類。
'''
# mysingleton.py
# class My_Singleton(object):
# def foo(self):
# pass
# my_singleton = My_Singleton()
# to use
from mysingleton import my_singleton
my_singleton.foo()
面試題:二維數組查找
#-*- coding:utf-8 -*-
'''
在一個二維數組中,每一行都按照從左到右遞增的順序排序
每一列都按照從上到下遞增的順序排序。
請完成一個函數,輸入這樣的一個二維數組和一個整數,判斷數組中是否含有該整數。
'''
'''
查找方式從右上角開始查找
如果當前元素大於target, 左移一位繼續查找
如果當前元素小於target, 下移一位繼續查找
進行了簡單的修改, 可以判定輸入類型爲字符的情況
'''
'''
如何出現了array中既有字符串,又有數字,可能需要用到ord()函數,這裏就不展開討論了
'''
class Solution:
#array 二維列表
def Find(self,target,array):
if array == [[]]:
return False
rawnum = len(array)
colnum = len(array[0])
#判斷非法輸入
#可以換成 isinstance(target,(int,float))進行判斷
if type(target) == float and type(array[0][0]) == int:
if int(target) == target:
return False
target = int(target)
elif type(target) == int and type(array[0][0]) == float:
target = float(int)
elif type(target) != type(array[0][0]): # 浮點數的相等判斷問題需要特別注意, 一般都是判斷兩個數的差值是否小於一個特別小的數。這裏不展開分析。
return False
j = colnum-1
i = 0
while i < rawnum and j >= 0:
if array[i][j] < target:
i += 1
elif array[i][j] > target:
j -= 1
else:
return True
return False
# 擴展, 輸出數組中target的個數
def searchMatrix(self,matrix,target):
if matrix == None or len(matrix) == 0:
return 0
rows = len(matrix)
cols = len(matrix[0])
row,col = 0,cols -1
count = 0
while row <= rows-1 and col >= 0:
if matrix[row][col] > target:
col -= 1
elif matrix[row][col] < target:
row += 1
else:
count += 1
col -= 1
return count
if __name__ == "__main__":
array = [[1, 2, 8, 9],
[2, 4, 9, 12],
[4, 7, 10, 13],
[6, 8, 11, 15]]
array2 = []
array3 = [['a', 'b', 'c'],
['b', 'c', 'd']]
array4 = [[62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80],
[63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81],
[64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82],
[65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83],
[66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84],
[67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85]]
solu = Solution()
print(solu.Find(30,array))
print(solu.searchMatrix(array4,81))
面試題:替換空格
'''
請實現一個函數,將一個字符串中的空格替換成“%20”。
例如,當字符串爲We Are Happy.則經過替換之後的字符串爲We%20Are%20Happy。
'''
# -*-coding:utf-8 -*-
class Solution(object):
# s 源字符串
# 使用append一次遍歷即可替換
# 由於list的append是o(1) 的時間複雜度,除了擴容所導致的時間損耗,該算法複雜度爲o(n)
def replaceSpaceByAppend(self,s):
s = list(s)
stringReplace = []
for item in s:
if item == ' ':
stringReplace.append('%')
stringReplace.append('2')
stringReplace.append('0')
else:
stringReplace.append(item)
return "".join(stringReplace)
#創建新的字符串進行替換
def replaceSpace1(self,s):
tempstr = ''
if type(s) != str:
return
for c in s:
if c == ' ':
tempstr += '%20'
else:
tempstr += c
return tempstr
#簡單代碼替換
#在Python中str類型是不可變的類型, 使用replace語句會生成一個新的str, 原始的s還是帶空格的str變量
def replaceSpace2(self,s):
if type(s) != str:
return
return s.replace(' ','%20')
#書中給的思路
# 判斷輸入類型的時候,isinstance必須首先判斷,因爲如果輸入爲integer的話,沒有len,就會直接報錯
def replaceSpace3(self,s):
if not isinstance(s,str) or len(s) <= 0 or s == None:
return ""
spaceNum = 0
for i in s:
if i == " ":
spaceNum += 1
newStrLen = len(s) + spaceNum*2
newStr = newStrLen*[None]
indexOfOriginal,indexOfNew = len(s) - 1,newStrLen - 1
while indexOfNew >= 0 and indexOfNew >= indexOfOriginal:
if s[indexOfOriginal] == ' ':
newStr[indexOfNew-2:indexOfNew+1] = ['%','2','0']
indexOfNew -= 3
indexOfOriginal -= 1
else:
newStr[indexOfNew] = s[indexOfOriginal]
indexOfNew -= 1
indexOfOriginal -= 1
return "".join(newStr)
if __name__ == "__main__":
s = 'we are happy'
test = Solution()
print(test.replaceSpace1(s))
print(test.replaceSpace2(s))
print(test.replaceSpace3(s))
面試題:反向打印鏈表
'''
輸入一個鏈表,從尾到頭打印鏈表每個節點的值。
'''
class ListNode:
def __init__(self,x=None):
self.val = x
self.next = None
class Solution(object):
def printListFromTailToHead(self,listNode):
if listNode == None:
return []
l = []
head = listNode
while head:
l.insert(0,head.val)
head = head.next
return l
if __name__=="__main__":
node1 = ListNode(10)
node2 = ListNode(11)
node3 = ListNode(13)
node1.next = node2
node2.next = node3
singleNode = ListNode(12)
test = ListNode()
S = Solution()
print(S.printListFromTailToHead(node1))
面試題:重建二叉樹
'''
輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建出該二叉樹。
假設輸入的前序遍歷和中序遍歷的結果中都不含重複的數字。
例如輸入前序遍歷序列{1,2,4,7,3,5,6,8}和中序遍歷序列{4,7,2,1,5,3,8,6},則重建二叉樹並返回。
'''
#-*- coding:utf - 8 -*-
class TreeNode:
def __init__(self,x):
self.val = x
self.left = None
self.right = None
class Solution(object):
#返回構造的TreeNode跟節點
def reConstructBinaryTree(self,pre,tin):
#write code here
if not pre and not tin:
return None
root = TreeNode(pre[0])
if set(pre) != set(tin):
return None
i = tin.index(pre[0])
root.left = self.reConstructBinaryTree(pre[1:i+1],tin[:i])
root.right = self.reConstructBinaryTree(pre[i+1:],tin[i+1:])
return root
# 按層序遍歷輸出樹中某一層的值
def PrintNodeAtLevel(self,treeNode,level):
if not treeNode or level < 0:
return 0
if level == 0:
print(treeNode.val)
return 1
self.PrintNodeAtLevel(treeNode.left,level-1)
self.PrintNodeAtLevel(treeNode.right,level-1)
# 已知樹的深度按層遍歷輸出的值
def PrintNodeByLevel(self, treeNode, depth):
for level in range(depth):
self.PrintNodeAtLevel(treeNode,level)
if __name__ == "__main__":
pre = [1, 2, 3, 5, 6, 4]
tin = [5, 3, 6, 2, 4, 1]
solu = Solution()
newTree = solu.reConstructBinaryTree(pre,tin)
#輸出一下第level層
#solu.PrintNodeAtLevel(newTree,1)#level表示第幾層的元素
solu.PrintNodeByLevel(newTree,5)
面試題:用兩個棧實現隊列
'''
用兩個棧來實現一個隊列,完成隊列的Push和Pop操作。 隊列中的元素爲int類型。
'''
#-*— coding:utf-8 -*-
class Queue(object):
def __init__(self):
self.stack1 = []
self.stack2 = []
def push(self,node):
self.stack1.append(node)
def pop(self):
if len(self.stack2) == 0 and len(self.stack1) == 0:
return
elif len(self.stack2) == 0:
while len(self.stack1) > 0:
self.stack2.append(self.stack1.pop())
return self.stack2.pop()
if __name__ == "__main__":
Q = Queue()
Q.push(10)
Q.push(11)
Q.push(12)
print(Q.pop())
Q.push(13)
print(Q.pop())
print(Q.pop())
print(Q.pop())
# -*- coding:UTF-8 -*-
'''
兩個隊列實現棧
'''
class Solution:
def __init__(self):
self.queue1 = []
self.queue2 = []
def push(self, x):
if self.queue2 == []:
self.queue1.append(x)
else:
self.queue2.append(x)
def pop(self):
if not self.queue1 and not self.queue2:
return
if self.queue1 != []:
length = len(self.queue1)
for i in range(length-1):
self.queue2.append(self.queue1.pop(0))
return self.queue1.pop()
else:
length = len(self.queue2)
for i in range(length-1):
self.queue1.append(self.queue2.pop(0))
return self.queue2.pop()
P = Solution()
P.push(10)
P.push(11)
P.push(12)
print(P.pop())
P.push(13)
print(P.pop())
print(P.pop())
print(P.pop())
print(P.pop())
面試題:旋轉數組的最小數字
'''
把一個數組最開始的若干個元素搬到數組的末尾,我們稱之爲數組的旋轉。
輸入一個遞增排序的數組的一個旋轉,輸出旋轉數組的最小元素。
例如數組{3,4,5,1,2}爲{1,2,3,4,5}的一個旋轉,該數組的最小值爲1。
NOTE:給出的所有元素都大於0,若數組大小爲0,請返回0。
'''
# -*- coding:utf-8 -*-
class Solution:
def minNumberInRotateArray(self, rotateArray):
if len(rotateArray) == 0:
return 0
front = 0
rear = len(rotateArray) - 1
minVal = rotateArray[0]
if rotateArray[front] < rotateArray[rear]:
return rotateArray[front]
else:
while (rear - front) > 1:
mid = (rear + front)//2
if rotateArray[mid] > rotateArray[rear]:
front = mid
elif rotateArray[mid] < rotateArray[front]:
rear = mid
elif rotateArray[mid] == rotateArray[front] and rotateArray[front] == rotateArray[rear]:
for i in range(1, len(rotateArray)):
if rotateArray[i] < minVal:
minVal = rotateArray[i]
rear = i
minVal = rotateArray[rear]
return minVal
# 書上方法
def minNumberInRotateArray2(self, rotateArray):
if len(rotateArray) == 0:
return 0
front, rear = 0, len(rotateArray) - 1
midIndex = 0
while rotateArray[front] >= rotateArray[rear]:
if rear - front == 1:
midIndex = rear
break
midIndex = (front + rear) // 2
if rotateArray[front] == rotateArray[rear] and rotateArray[front] == rotateArray[midIndex]:
return self.MinInOrder(rotateArray, front, rear)
if rotateArray[midIndex] >= rotateArray[front]:
front = midIndex
elif rotateArray[midIndex] <= rotateArray[rear]:
rear = midIndex
return rotateArray[midIndex]
def MinInOrder(self, array, front, end):
result = array[0]
for i in array[front:end+1]:
if i < result:
result = i
return result
Test = Solution()
print(Test.minNumberInRotateArray([3, 4, 5, 1, 2]))
print(Test.minNumberInRotateArray([1, 2, 3, 4, 5]))
print(Test.minNumberInRotateArray([1, 1, 1, 0, 1]))
print(Test.minNumberInRotateArray([1, 0, 1, 1, 1]))
print(Test.minNumberInRotateArray([]))
print(Test.minNumberInRotateArray([1]))
面試題:斐波那契數列
遞歸法:
class Solution1(object):
def Fibonacci(self,n):
if n <= 0:
return 0
if n == 1:
return 1
return self.Fibonacci(n-1)+self.Fibonacci(n-2)
動態規劃:
class Solution(object):
def Fibonacci(self,n):
if n <= 0:
return 0
if n == 1:
return n
tempList = [-1]*(n+1)
tempList[0]=0
tempList[1]=1
for i in range(2,n+1):
tempList[i] = tempList[i-1]+tempList[i-2]
return tempList[n]
面試題:跳臺階
一隻青蛙一次可以跳上1級臺階,也可以跳上2級。求該青蛙跳上一個n級的臺階總共有多少種跳法(先後次序不同算不同的結果)。
動態規劃:
class Solution(object):
def jumpFloor(self,number):
tempList = [-1]*(number+1)
if number <=1:
return 1
tempList[0] = 1
tempList[1] = 1
for i in range(2,number+1):
tempList[i] = tempList[i-1]+tempList[i-2]
return tempList[number]
面試題:跳臺階II
貪心法:
變態青蛙跳,每次至少跳一個,至多跳n個,一共有f(n)=2n-1種跳法。考察數學建模的能力。
class Solution(object):
def jumpFloorII(self, number):
ans = 1
if number >=2:
for i in range(number-1):
ans = ans*2
return ans
面試題:矩陣覆蓋
我們可以用21的小矩形橫着或者豎着去覆蓋更大的矩形。請問用n個21的小矩形無重疊地覆蓋一個2*n的大矩形,總共有多少種方法?
比如n=3時,2*3的矩形塊有3種覆蓋方法
class Solution(object):
def rectCover(self,number):
if number <= 2:
return number
else:
methods = []
for i in range(number):
if i <= 1:
methods.append(i+1)
else:
methods.append(methods[i-1]+methods[i-2])
return methods[number-1]
面試題:二進制中1的個數
輸入一個整數,輸出該數二進制表示中1的個數。其中負數用補碼錶示。
注意到每個非零整數n和n-1進行按位與運算,整數n的二進制數中最右邊的1就會變成0,那麼二進制數中的1的個數就會減少一個,因此可以利用一個循環,使得 n = n&(n-1) ,計算經過幾次運算減少到0,就是有幾個1。注意:書中給了另外兩種方法,分別是原始n左移一位和右移一位的方法,因爲python不會出現整數溢出的情況,這裏就不再考慮着兩種方法。擴展:判斷一個數值是不是2得整數次方,如果是的話,這個數的二進制數中有且只有一個1,那麼這個數n會有 n&(n-1) == 0。或者求兩個整數m和n需要改變m二進制中的多少位才能得到n,可以先做 m^n 的異或運算,然後求這個數中有多少個1。
方法1:
# -*- coding:utf-8 -*-
class Solution:
def NumberOf1(self, n):
# write code here
count = 0
if n < 0:
n = n & 0xffffffff
while n :
count += 1
n = (n-1)&n
return count
方法2:
class Solution(object):
def NumberOf1(self,n):
if n < 0:
s = bin(n&0xffffffff)
else:
s = bin(n)
return s.count('1')
面試題:數值的整數次方
給定一個double類型的浮點數base和int類型的整數exponent。求base的exponent次方。
保證base和exponent不同時爲0
class Solution(object):
def Power(self,base,exponent):
if exponent == 0:
return 1
if exponent == 1:
return base
if exponent == -1:
return 1/base
result = self.Power(base,exponent >> 1)
result *= result
if (exponent & 0x1) == 1:
result *= base
return result
面試題:打印1到最大的n位數
'''
輸入數字n, 按順序打印從1最大的n位十進制數
比如輸入3, 則打印出1、2、3、到最大的3位數即999
'''
def Print1ToMaxOfNDigits(n):
if n <= 0:
return
number = ['0'] * n
while not Increment(number):
PrintNumber(number)
def Increment(number):
isOverflow = False
nTakeOver = 0
nLength = len(number)
for i in range(nLength-1, -1, -1):
nSum = int(number[i]) + nTakeOver
if i == nLength - 1:
nSum += 1
if nSum >= 10:
if i == 0:
isOverflow = True
else:
nSum -= 10
nTakeOver = 1
number[i] = str(nSum)
else:
number[i] = str(nSum)
break
return isOverflow
def PrintNumber(number):
isBeginning0 = True
nLength = len(number)
for i in range(nLength):
if isBeginning0 and number[i] != '0':
isBeginning0 = False
if not isBeginning0:
print('%c' % number[i], end='')
print('')
#方法2
def Print1ToMaxOfNDigits2(n):
if n <= 0:
return
number = ['0'] * n
for i in range(10):
number[0] = str(i)
Print1ToMaxOfNDigitsRecursively(number, n, 0)
def Print1ToMaxOfNDigitsRecursively(number, length, index):
if index == length - 1:
PrintNumber(number)
return
for i in range(10):
number[index + 1] = str(i)
Print1ToMaxOfNDigitsRecursively(number, length, index+1)
面試題:在O(1)時間內刪除鏈表節點
'''
給定單向鏈表的頭指針和一個結點指針,定義一個函數在O(1)時間刪除該結點
'''
class ListNode:
def __init__(self, x=None):
self.val = x
self.next = None
def __del__(self):
self.val = None
self.next = None
class Solution:
def DeleteNode(self, pListHead, pToBeDeleted):
if not pListHead or not pToBeDeleted:
return None
if pToBeDeleted.next != None:
pNext = pToBeDeleted.next
pToBeDeleted.val = pNext.val
pToBeDeleted.next = pNext.next
pNext.__del__()
elif pListHead == pToBeDeleted:
pToBeDeleted.__del__()
pListHead.__del__()
else:
pNode = pListHead
while pNode.next != pToBeDeleted:
pNode = pNode.next
pNode.next = None
pToBeDeleted.__del__()
node1 = ListNode(10)
node2 = ListNode(11)
node3 = ListNode(13)
node4 = ListNode(15)
node1.next = node2
node2.next = node3
node3.next = node4
S = Solution()
S.DeleteNode(node1, node3)
print(node3.val)
S.DeleteNode(node1, node3)
print(node3.val)
print(node2.val)
S.DeleteNode(node1, node1)
print(node1.val)
S.DeleteNode(node1, node1)
print(node1.val)
面試題:調整數組順序使奇數位於偶數前面
常規方法:
# -*- coding:utf-8 -*-
class Solution:
def reOrderArray(self, array):
# write code here
if len(array) < 1:
return []
if len(array) == 1:
return array
arrayOdd = []
arrayEven = []
for num in array:
if num & 0x1:
arrayOdd.append(num)
else:
arrayEven.append(num)
return arrayOdd+arrayEven
Python 的小技巧
class Solution2(object):
def reOrderArray(self,array):
left = [x for x in array if x & 1]
right = [x for x in array if not x & 1]
return left + right
面試題:鏈表中倒數第K個節點
class ListNode(object):
def __init__(self,x=None):
self.val = x
self.next = None
class Solution(object):
def FindKthToTail(self,head,k):
if head == None or k <= 0:
return None
fast = head
slow = head
#快指針向前走k-1步
#但是移動除去就返回None
for i in range(k-1):
if fast.next != None:
fast = fast.next
else:
return None
while fast.next != None:
fast = fast.next
slow = slow.next
return slow
if __name__ == "__main__":
node1 = ListNode(10)
node2 = ListNode(11)
node3 = ListNode(12)
node4 = ListNode(13)
node5 = ListNode(14)
node1.next = node2
node2.next = node3
node3.next = node4
node4.next = node5
solu = Solution()
print(solu.FindKthToTail(node1,3).val)
面試題:反轉鏈表
class ListNode(object):
def __init__(self,x=None):
self.val = x
self.next = None
class Solution(object):
def ReverseList(self,head):
pReverseHead = None
currNode = head
preNode = None
while currNode != None:
nextNode = currNode.next
if nextNode == None:
pReverseHead = currNode
currNode.next = preNode
preNode = currNode
currNode = nextNode
return pReverseHead
遞歸實現
def ReverseListRec(self, pHead):
if not pHead or not pHead.next:
return pHead
else:
pReversedHead = self.ReverseList(pHead.next)
pHead.next.next = pHead
pHead.next = None
return pReversedHead
面試題:合併兩個排序鏈表
class ListNode(object):
def __init__(self,x=None):
self.val = x
self.next = None
class Solution(object):
def Merge(self,pHead1,pHead2):
if pHead1 == None:
return pHead2
if pHead2 == None:
return pHead1
pMergeHead = None
if pHead1.val < pHead2.val:
pMergeHead = pHead1
pMergeHead.next = self.Merge(pHead1.next,pHead2)
else:
pMergeHead = pHead2
pMergeHead.next = self.Merge(pHead1,pHead2.next)
return pMergeHead
面試題:樹的子結構
class TreeNode(object):
def __init__(self,x= None):
self.val = x
self.left = None
self.right = None
class Solution(object):
def HasSubtree(self,pRoot1,pRoot2):
result = None
if pRoot1 != None and pRoot2 != None:
if pRoot1.val == pRoot2.val:
result = self.DoesTree1haveTree2(pRoot1,pRoot2)
if not result:
result = self.HasSubtree(pRoot1.left,pRoot2)
if not result:
result = self.HasSubtree(pRoot1.right,pRoot2)
# 用於遞歸判斷樹的每個節點是否相同
# 需要注意的地方是: 前兩個if語句不可以顛倒順序
# 如果顛倒順序, 會先判斷pRoot1是否爲None, 其實這個時候pRoot2的結點已經遍歷完成確定相等了, 但是返回了False, 判斷錯誤
def DoesTree1haveTree2(self,pRoot1,pRoot2):
if pRoot2 == None:
return True
if pRoot1 == None:
return False
if pRoot1.val != pRoot2.val:
return False
return self.DoesTree1haveTree2(pRoot1.left,pRoot2.left) and self.DoesTree1haveTree2(pRoot1.right,pRoot2.right)
面試題:二叉樹的鏡像
遞歸實現
class TreeNode(object):
def __init__(self,x=None):
self.val = x
self.left = None
self.right = None
class Solution(object):
def Mirror(self,root):
if root == None:
return None
if root.left == None and root.right == None:
return root
root.left,root.right = root.right,root.left
self.Mirror(root.left)
self.Mirror(root.right)
非遞歸實現(超出時間限制)
class TreeNode(object):
def __init__(self,x= None):
self.val = x
self.left = None
self.right = None
class Solution(object):
def Mirror(self,root):
if root == None:
return None
nodeQueue = [root]
while len(nodeQueue) > 0:
curLevel,count=len(nodeQueue),0
while count<curLevel:
count += 1
pRoot = nodeQueue.pop(0)
pRoot.left,root.right = root.right,root.left
if pRoot.left:
nodeQueue.append(pRoot.left)
if pRoot.right:
nodeQueue.append(pRoot.right)
面試題:順時針打印矩陣
class Solution(object):
def printMatrix(self,matrix):
printArr = []
if matrix == None:
return None
if matrix == []:
return []
rows = len(matrix)
columns = len(matrix[0])
start = 0 #每次循環時的起點
while rows >start*2 and columns > start*2:
endX = columns - 1 - start
endY = rows - 1 - start
#從左到右加入到printArr
for i in range(start,endX+1):
number = matrix[start][i]
printArr.append(number)
#從上到下加入到printArr
if start < endY:
for i in range(start+1,endY+1):
number = matrix[i][endX]
printArr.append(number)
#從右到左加入到printArr
if start < endX and start < endY:
for i in range(endX-1,start-1,-1):
number = matrix[endY][i]
printArr.append(number)
#從下到上加入printArr
if start < endX and start < endY-1:
for i in range(endY-1,start,-1):
number = matrix[i][start]
printArr.append(number)
start += 1
return printArr
面試題:包含min函數的棧
class Solution(object):
def __init__(self):
self.stack = []
self.minStack = []
def push(self, x):
self.stack.append(x)
if self.minStack == [] or x < self.min():
self.minStack.append(x)
else:
self.minStack.append(self.min())
def pop(self):
if self.stack == [] or self.minStack == []:
return None
self.stack.pop()
self.minStack.pop()
def min(self):
if self.minStack==[]:
return None
return self.minStack[-1]
def top(self):
return self.stack[-1]
面試題:棧的壓入,彈出序列
輸入兩個整數序列,第一個序列表示棧的壓入順序,請判斷第二個序列是否可能爲該棧的彈出順序。假設壓入棧的所有數字均不相等。例如序列1,2,3,4,5是某棧的壓入順序,序列4,5,3,2,1是該壓棧序列對應的一個彈出序列,但4,3,5,1,2就不可能是該壓棧序列的彈出序列。(注意:這兩個序列的長度是相等的)
class Solution(object):
def IsPopOrder(self,pushV,popV):
if pushV == [] or popV == []:
return False
stack = []
for i in pushV:
stack.append(i)
while len(stack) and stack[-1] == popV[0]:
stack.pop()
popV.pop(0)
if len(stack) == 0:
return True
else:
return False
面試題:從上往下打印二叉樹
從上往下打印出二叉樹的每個節點,同層節點從左至右打印。
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
# 返回從上到下每個節點值列表,例:[1,2,3]
def PrintFromTopToBottom(self, root):
# write code here
res = []
queue = []
if root == None:
return []
queue.append(root)
while len(queue) > 0:
currRoot = queue.pop(0)
res.append(currRoot.val)
if currRoot.left:
queue.append(currRoot.left)
if currRoot.right:
queue.append(currRoot.right)
return res
面試題:二叉搜索樹的後續遍歷序列
輸入一個整數數組,判斷該數組是不是某二叉搜索樹的後序遍歷的結果。如果是則輸出Yes,否則輸出No。假設輸入的數組的任意兩個數字都互不相同。
'''
輸入一個整數數組,判斷該數組是不是某二叉搜索樹的後序遍歷的結果。
如果是則輸出Yes,否則輸出No。
假設輸入的數組的任意兩個數字都互不相同。
二叉搜索樹對於每一個非葉子節點, 均有結點左子節點<當前節點<結點右子節點
'''
class Solution(object):
def VerifySquenceOfBST(self,sequence):
if sequence == []:
return False
root = sequence[-1]
length = len(sequence)
#僅有左子樹或者右子樹是返回True
if min(sequence) > root or max(sequence) < root:
return True
index = 0
#二叉搜索樹的左子樹節點小於根節點
'''
下面這個for循環特別需要主要index=i必須寫在if語句外面,
否則就會發生當root結點前的所有元素小於root的時候, 正確判斷應該爲True,
但是因爲if語句沒有進入, index = 0 ,
在進入二叉搜索樹的右子樹結點大於根結點的for循環的時候, 因爲sequence的數都小於root, 就會判斷出錯
'''
for i in range(length-1):
index = i
if sequence[i] > root:
break
# 二叉搜索樹的右子樹結點大於根結點
# 這個循環中範圍起始點必須是index+1, 不能爲index
# 因爲當root結點前的所有元素小於root的時候,index=length-2,
# 此時sequence[index]<root, 但是按照range(index, length-1), 第一個元素sequence[j]==sequence[index] < root, 返回False, 實際應該返回True纔對
# 而使用index+1, 因爲已經默認index>root, 所以從後面一個開始盤算右子樹結點是否大於root, 也不會影響結果
for j in range(index+1,length-1):
if sequence[j] < root:
return False
#遞歸部分:
left = True
if index > 0:
left = self.VerifySquenceOfBST(sequence[:index])
right = True
if index < length-1:
right = self.VerifySquenceOfBST(sequence[index:length-1])
return left and right
面試題:二叉樹中和爲某一值的路徑
輸入一顆二叉樹的根節點和一個整數,打印出二叉樹中結點值的和爲輸入整數的所有路徑。路徑定義爲從樹的根結點開始往下一直到葉結點所經過的結點形成一條路徑。(注意: 在返回值的list中,數組長度大的數組靠前)
遞歸
class TreeNode(object):
def __init__(self,x):
self.val = x
self.left = None
self.right = None
class Solution(object):
def FindPath(self,root,expectNumber):
#返回二維列表,內部每個列表表示找到的路徑
if not root:
return []
if root.left == None and root.right == None:
if root.val == expectNumber:
return [[root.val]]
else:
return []
stack =[]
leftStack = self.FindPath(root.left,expectNumber-root.val)
for i in leftStack:
i.insert(0,root.val)
stack.append(i)
rightStack = self.FindPath(root.right,expectNumber-root.val)
for i in rightStack:
i.insert(0,root.val)
stack.append(i)
return stack
面試題:複雜鏈表的複製
輸入一個複雜鏈表(每個節點中有節點值,以及兩個指針,一個指向下一個節點,另一個特殊指針指向任意一個節點),返回結果爲複製後複雜鏈表的head。(注意,輸出結果中請不要返回參數中的節點引用,否則判題程序會直接返回空)
# -*- coding:utf-8 -*-
class RandomListNode:
def __init__(self, x):
self.label = x
self.next = None
self.random = None
class Solution:
# 返回 RandomListNode
def Clone(self, pHead):
if pHead == None:
return None
self.CloneNodes(pHead)
self.ConnectRandomNodes(pHead)
return self.ReconnectNodes(pHead)
# 複製原始鏈表的每個結點, 將複製的結點鏈接在其原始結點的後面
def CloneNodes(self, pHead):
pNode = pHead
while pNode:
pCloned = RandomListNode(0)
pCloned.label = pNode.label
pCloned.next = pNode.next
# pCloned.random = None #不需要寫這句話, 因爲創建新的結點的時候,random自動指向None
pNode.next = pCloned
pNode = pCloned.next
# 將複製後的鏈表中的複製結點的random指針鏈接到被複制結點random指針的後一個結點
def ConnectRandomNodes(self, pHead):
pNode = pHead
while pNode:
pCloned = pNode.next
if pNode.random != None:
pCloned.random = pNode.random.next
pNode = pCloned.next
# 拆分鏈表, 將原始鏈表的結點組成新的鏈表, 複製結點組成複製後的鏈表
def ReconnectNodes(self, pHead):
pNode = pHead
pClonedHead = pClonedNode = pNode.next
pNode.next = pClonedHead.next
pNode = pNode.next
while pNode:
pClonedNode.next = pNode.next
pClonedNode = pClonedNode.next
pNode.next = pClonedNode.next
pNode = pNode.next
return pClonedHead
面試題:二叉搜索樹與雙向鏈表
輸入一棵二叉搜索樹,將該二叉搜索樹轉換成一個排序的雙向鏈表。要求不能創建任何新的結點,只能調整樹中結點指針的指向。
class TreeNode(object):
def __init__(self,x):
self.val = x
self.left = None
self.right = None
class Solution(object):
def Convert(self,pRootOfTree):
if pRootOfTree == None:
return None
if not pRootOfTree.left and not pRootOfTree.right:
return pRootOfTree
#處理左子樹
self.Convert(pRootOfTree.left)
left = pRootOfTree.left
#連接根與左子樹最大結點
if left:
while left.right:
left = left.right
pRootOfTree.left,left.right = left,pRootOfTree
#處理右子樹
self.Convert(pRootOfTree.right)
right = pRootOfTree.right
#連接根與右子樹最小結點
if right:
while right.left:
right = right.left
pRootOfTree.right,right.left=right,pRootOfTree
while pRootOfTree.left:
pRootOfTree = pRootOfTree.left
return pRootOfTree
面試題:字符串的排列和組合
輸入一個字符串,按字典序打印出該字符串中字符的所有排列。例如輸入字符串abc,則打印出由字符a,b,c所能排列出來的所有字符串abc,acb,bac,bca,cab和cba。
class Solution(object):
def Permutation(self,ss):
if len(ss) == 0:
return []
if len(ss) == 1:
return list(ss)
charList = list(ss)
charList.sort()
res = []
for i in range(len(charList)):
if i > 0 and charList[i] == charList[i-1]:
continue
temp =self.Permutation(''.join(charList[:i])+''.join(charList[i+1:]))
for j in temp:
res.append(charList[i]+j)
return res
擴展習題, 生成字符的所有組合
比如輸入abc, 則他們的組合有[‘a’, ‘ab’, ‘abc’, ‘ac’, ‘b’, ‘bc’, ‘c’], ab和ba屬於不同的排列, 但屬於同一個組合
def group(self,ss):
if len(ss) == 0:
return []
if len(ss) == 1:
return list(ss)
charList = list(ss)
charList.sort()
res = []
for i in range(len(charList)):
res.append(charList[i])
if i > 0 and charList[i] == charList[i-1]:
continue
temp = self.group(''.join(charList[i+1:]))
for j in temp:
res.append(charList[i]+j)
res = list(set(res))
res.sort()
return res
面試題:數組中出現次數超過一半的數字
數組中有一個數字出現的次數超過數組長度的一半,請找出這個數字。例如輸入一個長度爲9的數組{1,2,3,2,2,2,5,4,2}。由於數字2在數組中出現了5次,超過數組長度的一半,因此輸出2。如果不存在則輸出0。
第一種思路,出現次數超過一半的數字,不管如何,必然這個數字位於數組中間的位置,因此可以採用類似於快排的劃分的方法,找到位於數組中間的位置的數字,然後在順序檢索是否這個數字出現次數超過一半。
有問題
在這裏插入代碼片
第二種思路根據數組的特點,出現次數超過一半的數,他出現的次數比其他數字出現的總和還要多,因此可以最開始保存兩個數值:數組中的一個數字以及它出現的次數,然後遍歷,如果下一個數字等於這個數字,那麼次數加一,如果不等,次數減一,當次數等於0的時候,在下一個數字的時候重新複製新的數字以及出現的次數置爲1,直到進行到最後,然後再驗證最後留下的數字是否出現次數超過一半,因爲可能前面的次數依次抵消掉,最後一個數字就直接是保留下來的數字,但是出現次數不一定超過一半。
class Solution:
# 基於Partition函數的O(n)算法
def MoreThanHalfNum_Solution(self, numbers):
length = len(numbers)
if numbers == None or length <= 0:
return 0
result = numbers[0]
times = 1
for i in range(1, length):
if times == 0:
result = numbers[i]
times = 1
elif numbers[i] == result:
times += 1
else:
times -= 1
if not self.CheckMoreThanHalf(numbers, length, result):
result = 0
return result
# 檢查查找到中位數的元素出現次數是否超過所有元素數量的一半
def CheckMoreThanHalf(self, numbers, length, number):
times = 0
for i in range(length):
if numbers[i] == number:
times += 1
if times*2 <= length:
return False
return True
面試題:最小的k個數
輸入n個整數,找出其中最小的K個數。例如輸入4,5,1,6,2,7,3,8這8個數字,則最小的4個數字是1,2,3,4,。
第一種方法是基於劃分的方法,如果是查找第k個數字,第一次劃分之後,劃分的位置如果大於k,那麼就在前面的子數組中進行繼續劃分,反之則在後面的子數組繼續劃分,時間複雜度O(n);
class Solution:
# O(n)的算法, 只有當我們可以修改輸入的數組時可用
# 基於Partition的方法
def GetLeastNumbers_Solution(self, tinput, k):
if tinput == None or len(tinput) < k or len(tinput) <= 0 or k <=0:
return []
n = len(tinput)
start = 0
end = n - 1
index = self.Partition(tinput, n, start, end)
while index != k-1:
if index > k-1:
end = index - 1
index = self.Partition(tinput, n, start, end)
else:
start = index + 1
index = self.Partition(tinput, n, start, end)
output = tinput[:k]
output.sort()
return output
def Partition(self, numbers, length, start, end):
if numbers == None or length <= 0 or start < 0 or end >= length:
return None
if end == start:
return end
pivotvlue = numbers[start]
leftmark = start + 1
rightmark = end
done = False
while not done:
while numbers[leftmark] <= pivotvlue and leftmark <= rightmark:
leftmark += 1
while numbers[rightmark] >= pivotvlue and rightmark >= leftmark:
rightmark -= 1
if leftmark > rightmark:
done = True
else:
numbers[leftmark], numbers[rightmark] = numbers[rightmark], numbers[leftmark]
numbers[rightmark], numbers[start] = numbers[start], numbers[rightmark]
return rightmark
第二種方法是可以適用於海量數據的方法,該方法基於二叉樹或者堆來實現,首先把數組前k個數字構建一個最大堆,然後從第k+1個數字開始遍歷數組,如果遍歷到的元素小於堆頂的數字,那麼久將換兩個數字,重新構造堆,繼續遍歷,最後剩下的堆就是最小的k個數,時間複雜度O(nlog k)。
有問題
在這裏插入代碼片
面試題:連續子數組的最大和
HZ偶爾會拿些專業問題來忽悠那些非計算機專業的同學。今天測試組開完會後,他又發話了:在古老的一維模式識別中,常常需要計算連續子向量的最大和,當向量全爲正數的時候,問題很好解決。但是,如果向量中包含負數,是否應該包含某個負數,並期望旁邊的正數會彌補它呢?例如:{6,-3,-2,7,-15,1,2,2},連續子向量的最大和爲8(從第0個開始,到第3個爲止)。給一個數組,返回它的最大連續子序列的和,你會不會被他忽悠住?(子向量的長度至少是1)
常規方法
# -*- coding:utf-8 -*-
class Solution:
def FindGreatestSumOfSubArray(self, array):
# write code here
if array == None or len(array)<=0:
return 0
nCurSum = 0
nGreatestSum = array[0]
for i in range(len(array)):
if nCurSum < 0:
nCurSum = array[i]
else:
nCurSum += array[i]
if nGreatestSum < nCurSum:
nGreatestSum = nCurSum
return nGreatestSum
動態規劃
# -*- coding:utf-8 -*-
class Solution:
def FindGreatestSumOfSubArray(self, array):
# write code here
if array == None or len(array)<=0:
return 0
aList = [0]*len(array)
for i in range(len(array)):
if i == 0 or aList[i-1] <= 0:
aList[i] = array[i]
else:
aList[i] = aList[i-1]+array[i]
return max(aList)
面試題:整數中1出現的次數(從1到n整數中1出現的次數)
數學規律:
# -*- coding:utf-8 -*-
class Solution:
def NumberOf1Between1AndN_Solution(self, n):
# write code herea
num_ones = 0
m = 1
while m <= n:
num_ones += (n // m + 8) // 10 * m + (n // m % 10 == 1) * (n % m + 1)
m *= 10
return num_ones
數學規律:
def NumberOf1Between1AndN2(self, n):
ones, m = 0, 1
while m <= n:
if ((n // m) % 10) != 0 and ((n // m) % 10) != 1:
ones += (n // 10 // m + 1) * m
elif ((n // m) % 10) == 1:
ones += (n // m // 10) * m + n % m + 1
m *= 10
return ones
面試題:把數組排成最小的數
一個。例如輸入數組{3,32,321},則打印出這三個數字能排成的最小數字爲321323。
# -*- coding:utf-8 -*-
class Solution:
def PrintMinNumber(self, numbers):
# write code here
if numbers == None or len(numbers) <= 0:
return ''
strList=[str(m) for m in numbers]
for i in range(len(numbers)-1):
for j in range(i+1,len(numbers)):
if strList[i]+strList[j] > strList[j]+strList[i]:
strList[i],strList[j] = strList[j],strList[i]
return ''.join(strList)
面試題:醜數
把只包含質因子2、3和5的數稱作醜數(Ugly Number)。例如6、8都是醜數,但14不是,因爲它包含質因子7。 習慣上我們把1當做是第一個醜數。求按從小到大的順序的第N個醜數。
解法:
空間換時間。建立一個長度爲n的數組,保存這n個醜數。在進行運算的時候,某個位置需要求得醜數一定是前面某個醜數乘以2、3或者5的結果,我們分別記錄之前乘以2後能得到的最大丑數M2,乘以3後能得到的最大丑數M3,乘以5後能得到的最大丑數M5,那麼下一個醜數一定是M2,M3,M5中的最小的那一個。同時注意到,已有的醜數是按順序存放在數組中的。對乘以2而言,肯定存在某一個醜數T2,排在他之前的每一個醜數乘以2得到的結果都會小於已有的最大丑數,在他之後的每一個醜數乘以2得到的結果都會太大,我們只需記下這個醜數的位置,每次生成新的醜數的時候,去更新這個T2。對於3和5同理。
# -*- coding:utf-8 -*-
class Solution:
def GetUglyNumber_Solution(self, index):
# write code here
if index == None or len(index)<= 0:
return 0
uglyNumbers = [1]*index
m = 1
index2= 0
index3 = 0
index5 = 0
while m < index:
minVal = min(uglyNumbers[index2]*2,uglyNumbers[index3]*3,uglyNumbers[index5]*5)
uglyNumbers[m] = minVal
while uglyNumbers[index2]*2 <= uglyNumbers[m]:
index2 += 1
while uglyNumbers[index3]*3 <= uglyNumbers[m]:
index3 += 1
while uglyNumbers[index5]*5 <= uglyNumbers[m]:
index5 += 1
m += 1
return uglyNumbers[-1]
面試題:第一個只出現一次的字符
在一個字符串(0<=字符串長度<=10000,全部由字母組成)中找到第一個只出現一次的字符,並返回它的位置, 如果沒有則返回 -1(需要區分大小寫).
# -*- coding:utf-8 -*-
class Solution:
def FirstNotRepeatingChar(self, s):
# write code here
if s == None or len(s) <= 0:
return -1
dict = {}
sList = list(s)
for i in sList:
if i not in dict:
dict[i] = 1
else:
dict[i] += 1
for i in range(len(sList)):
if dict[sList[i]] == 1:
return i
return -1
面試題:數組中的逆序對
解題思路:
這道題可以這麼想,我們要找到數組中的逆序對,**可以看做對數據進行排序,需要交換數組中的元素的次數,**但是防止相同大小的元素髮生交換,因此需要選擇一個穩定的排序方法,記錄發生交換的次數。那麼,基於比較的穩定的排序方法中,最快的方法就是歸併了,所以直接按照歸併排序的思路,將數組分解、合併、排序即可。但是需要注意的是,在常規歸併排序的時候,如果前一個元素大於後一個元素,直接進行交換即可,只進行了一次操作,但是對於這道題來講,對於每一次的歸併段,我們選擇從後向前遍歷,前面的歸併段的某一個數值left[i]如果大於後面的某一個數值right[j],因爲在right自己獨自排序的過程中,已經保證了right是有序的,所以j位置前面的數字全部小於right[j],所以在這裏逆序對的個數就會是 j-start-length,其中start是整個數組的起點,length是left的長度,然後再進行交換。
僅能通過50%測試用例
# -*- coding:utf-8 -*-
class Solution:
def InversePairs(self, data):
# write code here
if len(data) <= 0:
return 0
count = 0
copy=[]
for i in data:
copy.append(i)
copy.sort()
i = 0
while i < len(copy):
count += data.index(copy[i])
data.remove(copy[i])
i+=1
return count
歸併排序:
在這裏插入代碼片
面試題:兩個鏈表的第一個公共結點
首先依次遍歷兩個鏈表,記錄兩個鏈表的長度m和n,如果 m > n,那麼我們就先讓長度爲m的鏈表走m-n個結點,然後兩個鏈表同時遍歷,當遍歷到相同的結點的時候停止即可。對於 m < n,同理。
# -*- coding:utf-8 -*-
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def FindFirstCommonNode(self, pHead1, pHead2):
# write code here
nLength1 = self.GetListLength(pHead1)
nLength2 = self.GetListLength(pHead2)
nLengthDiff = abs(nLength1-nLength2)
if nLength1 > nLength2:
longOne = pHead1
shortOne = pHead2
else:
longOne = pHead2
shortOne = pHead1
for i in range(nLengthDiff):
longOne = longOne.next
while longOne != None and shortOne != None and longOne != shortOne:
longOne = longOne.next
shortOne = shortOne.next
pFirstCommonNode = longOne
return pFirstCommonNode
def GetListLength(self,pHead):
nLength = 0
while pHead != None:
pHead = pHead.next
nLength+= 1
return nLength
面試題:數字在排序數組中出現的次數
二分查找的擴展。可以構造兩個函數。第一個函數查找目標數字出現的最前面的位置,先使用二分查找找到該數字,如果該數字的index > 0而且該數字前面一個數字等於k的話,那麼就令end=middle-1,繼續二分查找。對於第二個函數,查找目標數字出現的最後面的位置,反之編寫。最後如果數字存在的話,令走後面的index減去最前面的index然後+1即可。在進行有序數組的元素查找,可以先嚐試一下二分查找
# -*- coding:utf-8 -*-
class Solution:
def GetNumberOfK(self, data, k):
# write code here
number = 0
if data != None and len(data)>0:
length = len(data)
first = self.GetFirstK(data,length,k,0,length-1)
last = self.GetLastK(data,length,k,0,length-1)
if first > -1:
number = last-first+1
return number
def GetFirstK(self,data,length,k,start,end):
if start > end:
return -1
mid = (start+end)//2
midData = data[mid]
if midData == k:
if mid > 0 and data[mid-1] == k:
end = mid-1
else:
return mid
elif midData > k:
end = mid-1
else:
start = mid +1
return self.GetFirstK(data,length,k,start,end)
def GetLastK(self,data,length,k,start,end):
if start > end:
return -1
mid =(start+end)//2
midData = data[mid]
if midData == k:
if mid < end and data[mid+1] == k:
start = mid+1
else:
return mid
elif midData > k:
end = mid-1
else:
start = mid+1
return self.GetLastK(data,length,k,start,end)
面試題:二叉樹的深度
輸入一棵二叉樹,求該樹的深度。從根結點到葉結點依次經過的結點(含根、葉結點)形成樹的一條路徑,最長路徑的長度爲樹的深度。
遞歸算法
class TreeNode(object):
def __init__(self,x):
self.val = x
self.left = None
self.right = None
class Solution(object):
def TreeDepth(self,pRoot):
if pRoot == None:
return 0
else:
return max(self.TreeDepth(pRoot.left),self.TreeDepth(pRoot.right))+1
非遞歸方法:利用一個棧和一個標誌位棧
class TreeNode(object):
def __init__(self,x):
self.val = x
self.left = None
self.right = None
class Solution(object):
def TreeDepth(self,pRoot):
if not pRoot:
return 0
depth = 0
stack = []
tag = []
pNode = pRoot
while pNode or stack:
while pNode:
stack.append(pNode)
tag.append(0)
pNode = pNode.left
if tag[-1] == 1:
depth = max(depth,len(stack))
stack.pop()
tag.pop()
pNode = None
else:
pNode = stack[-1]
pNode = pNode.right
tag.pop()
tag.append(1)
return depth
面試題:判斷平衡二叉樹
輸入一棵二叉樹,判斷該二叉樹是否是平衡二叉樹。
class TreeNode(object):
def __init__(self,x):
self.val = x
self.left = None
self.right = None
class Solution(object):
def IsBalanced_Solution(self,pRoot):
if pRoot == None:
return True
if abs(self.getDepth(pRoot.left)-self.getDepth(pRoot.right)) > 1:
return False
return self.IsBalanced_Solution(pRoot.left) and self.IsBalanced_Solution(pRoot.right)
def getDepth(self,pRoot):
if pRoot == None:
return 0
return max(self.getDepth(pRoot.left),self.getDepth(pRoot.right))+1
面試題:數組中只出現一次的數字
一個整型數組裏除了兩個數字之外,其他的數字都出現了兩次。請寫程序找出這兩個只出現一次的數字。
class Solution:
# 返回[a,b] 其中ab是出現一次的兩個數字
def FindNumsAppearOnce(self, array):
# write code here
res = []
dict = {}
for i in array:
if i not in dict:
dict[i] = 1
else:
dict[i] += 1
for i in dict.keys():
if dict[i] == 1:
res.append(i)
return res
面試題:和爲S的連續正數序列
小明很喜歡數學,有一天他在做數學作業時,要求計算出9~16的和,他馬上就寫出了正確答案是100。但是他並不滿足於此,他在想究竟有多少種連續的正數序列的和爲100(至少包括兩個數)。沒多久,他就得到另一組連續正數和爲100的序列:18,19,20,21,22。現在把問題交給你,你能不能也很快的找出所有和爲S的連續正數序列? Good Luck!
輸出描述:
輸出所有和爲S的連續正數序列。序列內按照從小至大的順序,序列間按照開始數字從小到大的順序
滑動窗口解法:
# -*- coding:utf-8 -*-
class Solution:
def FindContinuousSequence(self, tsum):
# write code here
"""
使用滑動窗口的方法來解決,
設定一個動態的窗口,p_low指向窗口頭部,
p_high指向窗口尾部,窗口之間的值,爲目標值。
如果目標值爲tsum,那就是其中一個解。否則移動窗口。
:param tsum:
"""
#判斷輸入要是小於3的話無解
if tsum < 3:
return []
#設定初始的滑動窗口大小
p_low = 1
p_high = 2
ans = []
while p_low < p_high:
#計算滑動窗口現在圈中的大小
cur_sum = sum(range(p_low,p_high+1))
if cur_sum == tsum:
#找到一組解
ans.append(range(p_low,p_high+1))
#移動滑動窗口並尋找下一組解
p_high = p_high+1
elif cur_sum <tsum:
p_high = p_high+1
else:
p_low=p_low+1
return ans
面試題:和爲s的兩個數字
輸入一個遞增排序的數組和一個數字S,在數組中查找兩個數,使得他們的和正好是S,如果有多對數字的和等於S,輸出兩個數的乘積最小的。
輸出描述:
對應每個測試案例,輸出兩個數,小的先輸出。
# 從左右一起查找
# 因爲當兩個數的和一定的時候, 兩個數字的間隔越大, 乘積越小
# 所以直接輸出查找到的第一對數即可
# -*- coding:utf-8 -*-
class Solution:
def FindNumbersWithSum(self, array, tsum):
# write code here
if array == None or len(array) <= 0 or array[-1]+array[-2]<tsum:
return []
start = 0
end = len(array)-1
while start < end:
sum =array[start]+array[end]
if sum < tsum:
start += 1
elif sum > tsum:
end -= 1
else:
return [array[start],array[end]]
return []
面試題:左旋轉字符串
題目描述
彙編語言中有一種移位指令叫做循環左移(ROL),現在有個簡單的任務,就是用字符串模擬這個指令的運算結果。對於一個給定的字符序列S,請你把其循環左移K位後的序列輸出。例如,字符序列S=”abcXYZdef”,要求輸出循環左移3位後的結果,即“XYZdefabc”。是不是很簡單?OK,搞定它!
class Solution(object):
def LeftRotateString(self,s,n):
if len(s) <= 0 or n < 0:
return ''
if len(s) == n:
return s
strList = list(s)
frontList = strList[:n]
behindList = strList[n:]
res = ''.join(behindList)+''.join(frontList)
return res
面試題:反轉單詞順序列
題目描述
牛客最近來了一個新員工Fish,每天早晨總是會拿着一本英文雜誌,寫些句子在本子上。同事Cat對Fish寫的內容頗感興趣,有一天他向Fish借來翻看,但卻讀不懂它的意思。例如,“student. a am I”。後來才意識到,這傢伙原來把句子單詞的順序翻轉了,正確的句子應該是“I am a student.”。Cat對一一的翻轉這些單詞順序可不在行,你能幫助他麼?
class Solution(object):
def ReverseSentence(self,s):
l = s.split(" ")
return ' '.join(l[::-1])
面試題:撲克牌順子
題目描述
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(object):
def IsContinuous(self,numbers):
if numbers == None or len(numbers) <= 0:
return False
# 把A,J,Q,K轉化一下
transDict = {'A':1,'J':11,'Q':12,'K':13}
for i in range(len(numbers)):
if numbers[i] in transDict.keys():
numbers[i] = transDict[numbers[i]]
numbers = sorted(numbers)
numberOfzero = 0
numberOfGap = 0
# 統計0的個數
i= 0
# 統計0的個數
i = 0
while i <len(numbers) and numbers[i] == 0:
numberOfzero += 1
i += 1
# 統計間隔的數目
small = numberOfzero
big = small + 1
while big < len(numbers):
#出現對子,不可能是順子
if numbers[small] == numbers[big]:
return False
numberOfGap += numbers[big] - numbers[small]-1
small = big
big += 1
return False if numberOfGap > numberOfzero else True
面試題:圓圈中最後剩下的數
題目描述
每年六一兒童節,牛客都會準備一些小禮物去看望孤兒院的小朋友,今年亦是如此。HF作爲牛客的資深元老,自然也準備了一些小遊戲。其中,有個遊戲是這樣的:首先,讓小朋友們圍成一個大圈。然後,他隨機指定一個數m,讓編號爲0的小朋友開始報數。每次喊到m-1的那個小朋友要出列唱首歌,然後可以在禮品箱中任意的挑選禮物,並且不再回到圈中,從他的下一個小朋友開始,繼續0…m-1報數…這樣下去…直到剩下最後一個小朋友,可以不用表演,並且拿到牛客名貴的“名偵探柯南”典藏版(名額有限哦!!_)。請你試着想下,哪個小朋友會得到這份禮品呢?(注:小朋友的編號是從0到n-1)
如果沒有小朋友,請返回-1
# -*- coding:utf-8 -*-
class Solution:
def LastRemaining_Solution(self, n, m):
# write code here
if n < 1 or m < 1:
return -1
remainIndex = 0
for i in range(1,n+1):
remainIndex = (remainIndex+m)%i
return remainIndex
面試題:求1+2+3+…+n
題目描述
求1+2+3+…+n,要求不能使用乘除法、for、while、if、else、switch、case等關鍵字及條件判斷語句(A?B:C)。
# -*- coding:utf-8 -*-
class Solution:
def Sum_Solution(self, n):
# write code here
return n and self.Sum_Solution(n-1)+n
面試題:不用加減乘除做加法
利用異或以及與進位求解
不能一個正數一個負數
可能是python的的整型可以無限大的原因, 導致正數和負數的異或操作不斷變成更小的負數而不會溢出
使用Swift嘗試了一下, 還是可以求得正數和負數的位操作相加運算的
超時
class Solution(object):
def Add(self,num1,num2):
while num2:
sum = num1^num2
carry = (num1&num2)<<1
num1 = sum
num2 = carry
return num1
#通過
通過每次對num1進行與操作保證是一個32位的整形
因此我們可以判斷符號位是否爲1做處理
class Solution(object):
def Add(self,num1,num2):
while num2 != 0:
temp = num1 ^ num2
num2 = (num1&num2) << 1
num1 = temp & 0xFFFFFFFF
return num1 if num1 >> 31 == 0 else num1 - 4294967296
面試題:把字符串轉換成整數
題目描述
將一個字符串轉換成一個整數,要求不能使用字符串轉換整數的庫函數。 數值爲0或者字符串不是一個合法的數值則返回0
輸入描述:
輸入一個字符串,包括數字字母符號,可以爲空
輸出描述:
如果是合法的數值表達則返回該數字,否則返回0
class Solution(object):
def StrToInt(self,s):
flag = False
if s == None or len(s) < 1:
return 0
numStack = []
dict = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}
for i in s:
if i in dict.keys():
numStack.append(dict[i])
elif i == '+':
continue
elif i == '-':
continue
else:
return 0
print(numStack)
ans = 0
if len(numStack) == 1 and numStack[0] == 0:
flag = True
return 0
for i in numStack:
ans = ans*10+i
if s[0] == '-':
ans = 0 - ans
return ans
面試題:數組中重複的數字
題目描述
在一個長度爲n的數組裏的所有數字都在0到n-1的範圍內。 數組中某些數字是重複的,但不知道有幾個數字是重複的。也不知道每個數字重複幾次。請找出數組中任意一個重複的數字。 例如,如果輸入長度爲7的數組{2,3,1,0,2,5,3},那麼對應的輸出是第一個重複的數字2。
class Solution:
# 這裏要特別注意~找到任意重複的一個值並賦值到duplication[0]
# 函數返回True/False
def duplicate(self, numbers, duplication):
if numbers == None or len(numbers) <= 0:
return False
for i in numbers:
if i < 0 or i > len(numbers) - 1:
return False
for i in range(len(numbers)):
while numbers[i] != i:
if numbers[i] == numbers[numbers[i]]:
duplication[0] = numbers[i]
return True
else:
index = numbers[i]
numbers[i], numbers[index] = numbers[index], numbers[i]
return False
面試題:構建乘積矩陣
題目描述
給定一個數組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]。不能使用除法。(注意:規定B[0] = A[1] * A[2] * … * A[n-1],B[n-1] = A[0] * A[1] * … * A[n-2];)
class Solution(object):
def multiply(self,A):
if A == None or len(A) <= 0:
return
length = len(A)
aList = [1] *length
for i in range(1,length):
aList[i] = aList[i-1]*A[i-1]
temp = 1
for i in range(length-2,-1,-1):
temp = temp * A[i+1]
aList[i] *= temp
return aList
面試題:正則表達式匹配
面試題:表示數值的字符串
題目描述
請實現一個函數用來判斷字符串是否表示數值(包括整數和小數)。例如,字符串"+100",“5e2”,"-123",“3.1416"和”-1E-16"都表示數值。 但是"12e",“1a3.14”,“1.2.3”,"±5"和"12e+4.3"都不是。
class Solution(object):
#s字符串
def isNumeric(self,s):
if s == None or len(s) <= 0:
return False
aList = [w.lower() for w in s]
if 'e' in aList:
indexE = aList.index('e')
front = aList[:indexE]
behind = aList[indexE+1:]
if '.' in behind or len(behind) == 0:
return False
isFront = self.scanDigit(front)
isBehind = self.scanDigit(behind)
return isBehind and isFront
else:
isNum = self.scanDigit(aList)
return isNum
def scanDigit(self,aList):
dotNum = 0
allowVal = ['0','1','2','3','4','5','6','7','8','9','+','-','.','e']
for i in range(len(aList)):
if aList[i] not in allowVal:
return False
if aList[i] == '.':
dotNum += 1
if aList[i] in '+-' and i != 0:
return False
if dotNum > 1:
return False
return True
# Python trick
def isNumeric2(self, s):
try:
float(s)
if s[0:2] != '-+' and s[0:2] != '+-':
return True
else:
return False
except:
return False
面試題:字符流中第一個不重複的字符
題目描述
請實現一個函數用來找出字符流中第一個只出現一次的字符。例如,當從字符流中只讀出前兩個字符"go"時,第一個只出現一次的字符是"g"。當從該字符流中讀出前六個字符“google"時,第一個只出現一次的字符是"l"。
輸出描述:
如果當前字符流沒有存在出現一次的字符,返回#字符。
class Solution(object):
def __init__(self):
self.aDict = {}
self.aList = []
def FirstAppearingOnce(self):
while len(self.aList) > 0 and self.aDict[self.aList[0]] == 2:
self.aList.pop(0)
if len(self.aList) == 0:
return '#'
else:
return self.aList[0]
def Insert(self,char):
if char not in self.aDict.keys():
self.aDict[char] = 1
self.aList.append(char)
elif self.aDict[char]:
self.aDict[char] = 2
面試題:鏈表中環的入口結點
題目描述
給一個鏈表,若其中包含環,請找出該鏈表的環的入口結點,否則,輸出null。
尋找鏈表中環的入口結點主要分成三個步驟:首先是設置兩個快慢指針,如果快慢指針相遇,則快慢指針必然都在環中;然後從相遇的地方設置一個指針向後遍歷並記錄走的步數,當這個指針重新指到開始的位置的時候,當前對應的步數就是環中結點的數量k;然後設置兩個指針從鏈表開始,第一個節點先走k步,然後第二個指針指到鏈表的開始,兩個指針每次都向後走一步,兩個指針相遇的位置就是鏈表的入口。
class ListNode:
def __init__(self,x):
self.val = x
self.next = None
class Solution(object):
def MeetingNode(self,pHead):
if pHead == None:
return None
pSlow = pHead.next
if pSlow == None:
return None
pFast = pSlow.next
while pFast:
if pFast == pSlow:
return pSlow
pSlow = pSlow.next
pFast = pFast.next
if pFast:
pFast = pFast.next
def EntryNodeOfLoop(self,pHead):
meetingNode = self.MeetingNode(pHead)
if not meetingNode:
return None
NodeLoop = 1
flagNode = meetingNode
while flagNode.next != meetingNode:
NodeLoop += 1
flagNode = flagNode.next
pFast = pHead
for i in range(NodeLoop):
pFast = pFast.next
pSlow = pHead
while pFast != pSlow:
pFast = pFast.next
pSlow = pSlow.next
return pFast
面試題:刪除鏈表中重複的結點
我們需要設置一個指針preNode,preNode最開始爲None,然後設置兩個指針,pNode指向當前節點,pNext指向pNode下一個結點,⓵如果pNext不爲空而且pNext的值等於pNode的值,那麼就說明出現了重複數字的結點,就需要刪除,然後從pNode開始遍歷,如果結點值等於前面那個重複值,繼續遍歷。當遍歷到None或者不同值結點的時候,這時候需要判斷preNode結點,如果preNode結點爲None,就說明我們剛纔的重複結點是從整個鏈表的頭結點開始重複的,就直接把pHead設置爲當前結點,pNode也設置爲當前結點。反之,如果preNode不爲None,直接把preNode的下一個指針指向當前節點,pNode指向preNode即可;⓶如果pNext爲空或者pNext的值不等於pNode的值,說明當前的這個pNode和後面的值不重複,直接令preNode = pNode,pNode指向下一個結點即可。
class ListNode(object):
def __init__(self,x):
self.val = x
self.next = None
class Solution(object):
def deleteDuplication(self,pHead):
if pHead == None:
return
preHead = None
pNode = pHead
while pNode != None:
needDelete = False
nextNode = pNode.next
if nextNode != None and nextNode.val == pNode.val:
needDelete = True
if needDelete == False:
preHead = pNode
pNode = pNode.next
else:
nodeVal = pNode.val
pToBeDel = pNode
while pToBeDel != None and pToBeDel.val == nodeVal:
pToBeDel = pToBeDel.next
if preHead == None:
pHead = pToBeDel
pNode = pToBeDel
continue
else:
preHead.next = pToBeDel
pNode = preHead
return pHead
面試題:二叉樹的下一個結點
三種情況:當前節點有右子樹的話,當前節點的下一個結點是右子樹中的最左子節點;當前節點無右子樹但是是父節點的左子節點,下一個節點是當前結點的父節點;當前節點無右子樹而且是父節點的右子節點,則一直向上遍歷,直到找到最靠近的一個祖先節點pNode,pNode是其父節點的左子節點,那麼輸入節點的下一個結點就是pNode的父節點。
class TreeLinkNode:
def __init__(self,x):
self.val = x
self.left = None
self.right = None
self.next = None
class Solution(object):
def GetNext(self,pNode):
if pNode == None:
return
pNext = None
if pNode.right != None:
pRight = pNode.right
while pRight.left != None:
pRight = pRight.left
pNext = pRight
elif pNode != None:
pCurrent = pNode
pParent = pCurrenrt
while pParent != None and pCurrent == pParent.right:
pCurrent = pParent
pParent = pCurrent.next
pNext = pParent
return pNext
面試題:對稱的二叉樹
分爲遞歸和非遞歸的兩種方式,思想是一樣的。主要就是把葉子節點的None節點也加入到遍歷當中。按照前序遍歷二叉樹,存入一個序列中。然後按照和前序遍歷對應的先父節點,然後右子節點,最後左子節點遍歷二叉樹,存入一個序列。如果前後兩個序列相等,那麼說明二叉樹是對稱的。
遞歸法:
class TreeNode(object):
def __init__(self,x):
self.val = x
self.left = None
self.right = None
class Solution(object):
def isSymmetrical(self, pRoot):
return self.selfIsSymmetrical(pRoot,pRoot)
def selfIsSymmetrical(self,pRoot1,pRoot2):
if pRoot1 == None and pRoot2 == None:
return True
if pRoot1 == None or pRoot2 == None:
return False
if pRoot1.val != pRoot2.val:
return False
return self.selfIsSymmetrical(pRoot1.left,pRoot2.right) and self.selfIsSymmetrical(pRoot1.right,pRoot2.left)
非遞歸實現判斷二叉樹是否對稱
#利用前序遍歷
class Solution2:
def isSymmetrical(self, pRoot):
preList = self.preOrder(pRoot)
mirrorList = self.mirrorPreOrder(pRoot)
if preList == mirrorList:
return True
return False
def preOrder(self, pRoot):
if pRoot == None:
return [None]
treeStack = []
output = []
pNode = pRoot
while pNode or len(treeStack) > 0:
while pNode:
treeStack.append(pNode)
output.append(pNode.val)
pNode = pNode.left
if not pNode:
output.append(None)
if len(treeStack):
pNode = treeStack.pop()
pNode = pNode.right
if not pNode:
output.append(None)
return output
def mirrorPreOrder(self, pRoot):
if pRoot == None:
return [None]
treeStack = []
output = []
pNode = pRoot
while pNode or len(treeStack) > 0:
while pNode:
treeStack.append(pNode)
output.append(pNode.val)
pNode = pNode.right
if not pNode:
output.append(None)
if len(treeStack):
pNode = treeStack.pop()
pNode = pNode.left
if not pNode:
output.append(None)
return output
面試題:把二叉樹打印成多行
題目描述
從上到下按層打印二叉樹,同一層結點從左至右輸出。每一層輸出一行。
class TreeNode(object):
def __init__(self,x):
self.val = x
self.left = None
self.right = None
class Solution(object):
def Print(self,pRoot):
if pRoot == None:
return []
nodes,res = [pRoot],[]
while nodes:
curStack,nextStack = [],[]
for node in nodes:
curStack.append(node.val)
if node.left:
nextStack.append(node.left)
if node.right:
nextStack.append(node.right)
res.append(curStack)
nodes = nextStack
return res
面試題:按之字形順序打印二叉樹
class TreeNode(object):
def __init__(self,x):
self.val = x
self.left = None
self.right = None
class Solution(object):
def Serialize(self,root):
serializeStr = ''
if root == None:
return '#'
stack = []
while root or stack:
while root:
serializeStr += str(root.val) + ','
stack.append(root)
root = root.left
serializeStr += '#,'
root = stack.pop()
root = root.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
面試題:序列化二叉樹
class TreeNode(object):
def __init__(self,x):
self.val = x
self.left = None
self.right = None
class Solution(object):
def Serialize(self,root):
serializeStr = ''
if root == None:
return '#'
stack = []
while root or stack:
while root:
serializeStr += str(root.val) + ','
stack.append(root)
root = root.left
serializeStr += '#,'
root = stack.pop()
root = root.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
面試題:二叉搜索樹的第k個結點
‘’’
給定一顆二叉搜索樹,請找出其中的第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:
#返回對應結點TreeNode
def __init__(self):
self.treeNode = []
def inOrder(self,pRoot):
if len(self.treeNode) < 0:
return None
if pRoot.left:
self.inOrder(pRoot.left)
self.treeNode.append(pRoot)
if pRoot.right:
self.inOrder(pRoot.right)
def KthNode(self,pRoot,k):
if k == 0 or pRoot == None:
return
self.inOrder(pRoot)
if len(self.treeNode) < k:
return None
return self.treeNode[k-1]
面試題:
題目描述
如何得到一個數據流中的中位數?如果從數據流中讀出奇數個數值,那麼中位數就是所有數值排序之後位於中間的數值。如果從數據流中讀出偶數個數值,那麼中位數就是所有數值排序之後中間兩個數的平均值。我們使用Insert()方法讀取數據流,使用GetMedian()方法獲取當前讀取數據的中位數。
class Solution(object):
def __init__(self):
self.nums = []
def Insert(self,num):
self.nums.append(num)
def GetMedian(self,n=None):
self.nums.sort()
if len(self.nums)%2 == 0:
res = (self.nums[len(self.nums)/2] + self.nums[len(self.nums)/2-1])/2.0
else:
res = self.nums[len(self.nums)//2]
return res
面試題:滑動窗口的最大值
題目描述
給定一個數組和滑動窗口的大小,找出所有滑動窗口裏數值的最大值。例如,如果輸入數組{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]}。
我們把可能成爲滑動窗口的最大值的數值下標存入一個兩端開口的隊列index中。
首先遍歷輸入數組,在遍歷次數小於窗口長度的時候,如果index數組裏面含有元素而且元素後面的下標值對應的輸入數組的數如果小於當前遍歷到的輸入數組元素值,那麼就把尾部的元素下標值不斷pop出來,再壓入當前輸入元素對應的下標值。然後再從等於滑動窗口大小的位置繼續遍歷輸入數組。首先把index數組的頭元素下標值對應輸入數組值壓入輸出數組。同樣的,如果index數組裏面含有元素而且元素後面的下標值對應的輸入數組的數如果小於當前遍歷到的輸入數組元素值,那麼就把尾部的元素下標值不斷pop出來,同時,如果index數組內有元素,而且當一個數字的下標與當前處理的數字的下標只差大於或等於滑動窗口的大小時,這個數字已經從窗口中畫出,可以從隊列中刪除了,再壓入當前輸入元素對應的下標值。最後還需要在輸出數組中append一下index手元素下標對應的輸入元素值。
class Solution(object):
def maxInWindows(self,num,size):
if not num 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
面試題:矩陣中的路徑
回溯法:
任選一個格子作爲路徑的起點。假設矩陣中某個格子的字符爲ch並且這個格子將對應於路徑上的第i個字符。如果路徑上的第i個字符不是ch,那麼這個格子不可能處在路徑上的第i個位置。如果路徑上的第i個字符正好是ch,那麼往相鄰的格子尋找路徑上的第i+1個字符。除在矩陣邊界上的格子外,其他各自都有4個相鄰的格子。重複這個過程直到路徑上的所有字符都在矩陣中找到相應的位置。
class Solution(object):
def hasPath(self,matrix,rows,cols,path):
if matrix == None or rows < 1 or cols < 1 or path == None:
return False
visited = [0] * [rows * cols]
for row in range(rows):
for col in range(cols):
self.hasPathCore(matrix,rows,cols,row,col,path,pathLength,visited)
面試題:機器人的運動範圍
題目描述
地上有一個m行和n列的方格。一個機器人從座標0,0的格子開始移動,每一次只能向左,右,上,下四個方向移動一格,但是不能進入行座標和列座標的數位之和大於k的格子。 例如,當k爲18時,機器人能夠進入方格(35,37),因爲3+5+3+7 = 18。但是,它不能進入方格(35,38),因爲3+5+3+8 = 19。請問該機器人能夠達到多少個格子?
class Solution(object):
def movingCount(self,threshold,rows,cols):
visited = [False] * (rows * cols)
count = self.movingCountCore(threshold,rows,cols,0,0,visited)
return count
def movingCountCore(self,threshold,rows,cols,row,col,visited):
count = 0
if self.check(threshold,rows,cols,row,col,visited):
visited[row*cols+col] = True
count = 1 +self.movingCountCore(threshold,rows,cols,row-1,col,visited) + \
self.movingCountCore(threshold,rows,cols,row+1,col,visited) + \
self.movingCountCore(threshold,rows,cols,row,col-1,visited) + \
self.movingCountCore(threshold,rows,cols,row,col+1,visited)
return count
def check(self,threshold,rows,cols,row,col,visited):
if row >= 0 and row < rows and col >= 0 and col < cols and self.getDigitSum(row) + self.getDigitSum(col) <= threshold and not visited[row*cols+col]:
return True
return False
def getDigitSum(self,number):
sum = 0
while number > 0:
sum += (number % 10)
number = number// 10
return sum
面試題:剪繩子
題目描述
給你一根長度爲n的繩子,請把繩子剪成整數長的m段(m、n都是整數,n>1並且m>1),每段繩子的長度記爲k[0],k[1],…,k[m]。請問k[0]xk[1]x…xk[m]可能的最大乘積是多少?例如,當繩子的長度是8時,我們把它剪成長度分別爲2、3、3的三段,此時得到的最大乘積是18。
動態規劃
class Solution:
def cutRope(self, number):
# write code here
if number < 2:
return 0
if number == 2:
return 1
if number == 3:
return 2
dp = [-1]*(number+1)
dp[0] = 0
dp[1] = 1
dp[2] = 2
dp[3] = 3
for i in range(4,number+1):
max = 0
for j in range(1,i//2 + 1):
temp = dp[j] * dp[i-j]
if temp > max:
max = temp
dp[i] = max
return dp[number]
貪心
class Solution:
def cutRope(self, number):
# write code here
res=1
if number<=1:
return 0
elif number<=2:
return 1
elif number<=3:
return 2
elif number>3:
if number%3==0:
res=3**(number//3)
elif number%3==1:
res=3**(number//3-1)*4
else:
res=3**(number//3)*(number%3)
return res