牛客网剑指offer编程实践51-66题
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]。不能使用除法。
解答:
方法:
B[i]**的值可以看作下圖的矩陣中每行的乘積。**
下三角用連乘可以很容求得,上三角,從下向上也是連乘。
因此我們的思路就很清晰了,先算下三角中的連乘,即我們先算出B[i]中的一部分,然后倒過來按上三角中的分布規律,把另一部分也乘進去。
?
# -*- coding:utf-8 -*- class Solution:def multiply(self, A):# write code hereB = [1] * len(A)B[0] = 1for i in range(1,len(A)):B[i] = B[i-1] * A[i-1]tmp = 1for j in reversed(range(0,len(A)-1)):tmp *= A[j+1]B[j] = B[j] * tmpreturn B52、正則表達式匹配
請實現一個函數用來匹配包括'.'和''的正則表達式。模式中的字符'.'表示任意一個字符,而''表示它前面的字符可以出現任意次(包含0次)。 在本題中,匹配是指字符串的所有字符匹配整個模式。例如,字符串"aaa"與模式"a.a"和"abaca"匹配,但是與"aa.a"和"ab*a"均不匹配
解答:
方法:考慮情況
1、s和pattern同時為空時,返回True
2、s不為空,pattern為空時,返回False
3、s為空,pattern不為空時,需要判斷pattern[1]是否為’’,注意這里還要判斷len(pattern) > 1,如果滿足,則pattern后移兩位繼續判斷,因為可能有’’,’abc’的情況;否則直接返回False;
4、如果s不為空,pattern[1] == ‘*’時,這時分為兩種情況判斷:
1)如果s[0] != pattern[0]時,pattern后移兩位繼續判斷
2)s[0] == pattern[0] or pattern[0] == ‘.’時分三種情況:
A)pattern后移2個,s不變;相當于把pattern前兩位當成空,匹配后面的
B)pattern后移2個,s后移1個;相當于pattern前兩位與s[0]匹配,A和B可以結合在一起
C)pattern不變,s后移1個;相當于pattern前兩位,與s中的多位進行匹配,因為*可以匹配多位
5)pattern[1] != ‘*’時,如果s[0] == pattern[0] or pattern[0] == ‘.’,則s后移1位,pattern后移一位繼續判斷,否則返回False
# -*- coding:utf-8 -*- class Solution:# s, pattern都是字符串def match(self, s, pattern):# write code hereif len(s) == 0 and len(pattern) == 0:return Trueif len(s) != 0 and len(pattern) == 0:return Falseif len(s) == 0 and len(pattern) != 0:if len(pattern) > 1 and pattern[1] == '*':return self.match(s,pattern[2:])return Falseelse:if len(pattern) > 1 and pattern[1] == '*':if s[0] == pattern[0] or pattern[0] == '.':return self.match(s[1:],pattern) or self.match(s,pattern[2:])else:return self.match(s,pattern[2:])else:if s[0] == pattern[0] or pattern[0] == '.':return self.match(s[1:],pattern[1:])else:return False53、 表示數值的字符串
請實現一個函數用來判斷字符串是否表示數值(包括整數和小數)。例如,字符串"+100","5e2","-123","3.1416"和"-1E-16"都表示數值。 但是"12e","1a3.14","1.2.3","+-5"和"12e+4.3"都不是。
解答:
方法:
1、e后面一定要接數字
2、不能同時存在兩個e
3、第二次出現+-符號,則必須緊接在e之后
4、第一次出現+-符號,且不是在字符串開頭,則也必須緊接在e之后
5、e后面不能接小數點,小數點不能出現兩次
6、不能出現不合法字符,只能在0-9
7、+、-、.單獨出現時返回False
# -*- coding:utf-8 -*- class Solution:# s字符串def isNumeric(self, s):# write code heresymbol = Falsepoint = FalsehasE = Falsefor i in range(len(s)):if s[i] == 'e' or s[i] == 'E':if hasE or i == len(s) - 1:return FalsehasE = Truecontinueif s[i] == '.':if hasE or point:return Falseif i == 0 and len(s) == 1:return Falsepoint = Truecontinueif s[i] == '+' or s[i] == '-':if symbol and s[i-1] != 'e' and s[i-1] != 'E':return Falseelif not symbol and i != 0 and s[i-1] != 'e' and s[i-1] != 'E':return Falseelif i == 0 and len(s) == 1:return Falsesymbol = Truecontinueif s[i] > '9' or s[i] < '0':return Falsereturn True54、字符流中第一個不重復的字符
請實現一個函數用來找出字符流中第一個只出現一次的字符。例如,當從字符流中只讀出前兩個字符"go"時,第一個只出現一次的字符是"g"。當從該字符流中讀出前六個字符“google"時,第一個只出現一次的字符是"l"。
輸出:如果當前字符流沒有存在出現一次的字符,返回#字符。
解答:
方法:字典
# -*- coding:utf-8 -*- class Solution:# 返回對應chardef __init__(self):self.s = ''self.s_dict = {}def FirstAppearingOnce(self):# write code herefor i in self.s:if self.s_dict[i] == 1:return ireturn '#'def Insert(self, char):# write code hereself.s += charif char not in self.s_dict:self.s_dict[char] = 0self.s_dict[char] += 155、鏈表中環的入口結點
給一個鏈表,若其中包含環,請找出該鏈表的環的入口結點,否則,輸出null。
解答:
1、第一步,找環中相匯點。分別用p1,p2指向鏈表頭部,p1每次走一步,p2每次走二步,直到p1==p2找到在環中的相匯點。
2、第二步,找環的入口。接上步,當p1=p2時,p2所經過節點數為2x,p1所經過節點數為x,設環中有n個節點,p2比p1多走m圈有2x= mn+x; mn=x;可以看出p1實際走了一個環的步數,再讓p2指向鏈表頭部,p1位置不變,p1,p2每次走一步直到p1=p2; 此時p1指向環的入口。
?
# -*- coding:utf-8 -*- # class ListNode: # ? ? def __init__(self, x): # ? ? ? ? self.val = x # ? ? ? ? self.next = None class Solution:def EntryNodeOfLoop(self, pHead):# write code hereif not pHead or not pHead.next:return Nonep1 = pHeadp2 = pHeadwhile pHead and pHead.next:p1 = p1.nextp2 = p2.next.nextif p1 == p2:p2 = pHeadwhile p1 != p2:p2 = p2.nextp1 = p1.nextreturn p1return None56、 刪除鏈表中重復的結點
在一個排序的鏈表中,存在重復的結點,請刪除該鏈表中重復的結點,重復的結點不保留,返回鏈表頭指針。 例如,鏈表1->2->3->3->4->4->5 處理后為 1->2->5
解答:
方法:
1->2->3->4->2,不會刪除2,只會刪除連續重復的結點
1、設置一個空結點first,first.next = pHead,目的是解決頭指針重復的情況
2、設置last = first,作為刪除結點的前一個結點,目的是能夠保證鏈表不斷。
# -*- coding:utf-8 -*- # class ListNode: # ? ? def __init__(self, x): # ? ? ? ? self.val = x # ? ? ? ? self.next = None class Solution:def deleteDuplication(self, pHead):# write code herefirst = ListNode(None)first.next = pHeadp = pHeadlast = firstif not pHead:return Nonewhile p and p.next:if p.val == p.next.val:p_val = p.valwhile p and p.val == p_val:p = p.nextlast.next = pelse:last = pp = p.nextreturn first.next57、 二叉樹的下一個結點
給定一個二叉樹和其中的一個結點,請找出中序遍歷順序的下一個結點并且返回。注意,樹中的結點不僅包含左右子結點,同時包含指向父結點的指針。
解答:
方法:
1、結點為空,返回空
2、結點的右子樹存在,找到其右子樹最左邊的結點
3、結點位于其父結點的左子樹,則下個結點就是其父結點
4、結點位于其父結點的右子樹,向上尋找父結點,直到找到一個結點是其父結點的左結點,這個父結點就是下個結點
# -*- coding:utf-8 -*- # class TreeLinkNode: # ? ? def __init__(self, x): # ? ? ? ? self.val = x # ? ? ? ? self.left = None # ? ? ? ? self.right = None # ? ? ? ? self.next = None class Solution:def GetNext(self, pNode):# write code hereif not pNode:return Noneif pNode.right:node = pNode.rightwhile node.left:node = node.leftreturn nodewhile pNode.next:pRoot = pNode.nextif pRoot.left == pNode:return pRootpNode = pNode.nextreturn None58、對稱的二叉樹
請實現一個函數,用來判斷一顆二叉樹是不是對稱的。注意,如果一個二叉樹同此二叉樹的鏡像是同樣的,定義其為對稱的。
解答:程序
方法1:遞歸
方法2:非遞歸
利用堆棧,成對進棧和出棧
需要注意,這里是continue而不是return Ture
?
# -*- coding:utf-8 -*- # class TreeNode: # ? ? def __init__(self, x): # ? ? ? ? self.val = x # ? ? ? ? self.left = None # ? ? ? ? self.right = None class Solution:def isSymmetrical(self, pRoot):return self.isSymmetrical_part(pRoot,pRoot) ?def isSymmetrical_part(self,pRoot1,pRoot2):if not pRoot1 and not pRoot2:return Trueif not pRoot1 or not pRoot2:return Falseif pRoot1.val != pRoot2.val:return Falsereturn self.isSymmetrical_part(pRoot1.left,pRoot2.right) and self.isSymmetrical_part(pRoot1.right,pRoot2.left)def isSymmetrical(self, pRoot):# write code hereres = []if not pRoot:return TruepRoot_left = pRoot.leftpRoot_right = pRoot.rightres.append(pRoot_left)res.append(pRoot_right)while res:p_right = res.pop()p_left = res.pop()if not p_left and not p_right:continueif not p_left or not p_right:return Falseif p_left.val != p_right.val:return Falseres.append(p_left.left)res.append(p_right.right)res.append(p_left.right)res.append(p_right.left)return True59、按之字形順序打印二叉樹
請實現一個函數按照之字形打印二叉樹,即第一行按照從左到右的順序打印,第二層按照從右至左的順序打印,第三行按照從左到右的順序打印,其他行以此類推。
解答:
方法:
層次遍歷,奇數層正序輸出,偶數層倒序輸出
# -*- coding:utf-8 -*- # class TreeNode: # ? ? def __init__(self, x): # ? ? ? ? self.val = x # ? ? ? ? self.left = None # ? ? ? ? self.right = None class Solution:def Print(self, pRoot):# write code hereif not pRoot:return []stack = []node = pRootsum_count = 1count = 0depth = 1stack.append(node)res = []result = []while stack:node = stack.pop(0)count += 1res.append(node.val)if node.left:stack.append(node.left)if node.right:stack.append(node.right)if count == sum_count:sum_count = len(stack)if depth % 2 != 0:result.append(res)else:res.reverse()result.append(res)count = 0depth += 1res = []return result60、 把二叉樹打印成多行
從上到下按層打印二叉樹,同一層結點從左至右輸出。每一層輸出一行。
解答:
方法:
層次遍歷
# -*- coding:utf-8 -*- # class TreeNode: # ? ? def __init__(self, x): # ? ? ? ? self.val = x # ? ? ? ? self.left = None # ? ? ? ? self.right = None class Solution:# 返回二維列表[[1,2],[4,5]]def Print(self, pRoot):# write code hereif not pRoot:return []stack = []node = pRootsum_count = 1count = 0stack.append(node)res = []result = []while stack:node = stack.pop(0)count += 1res.append(node.val)if node.left:stack.append(node.left)if node.right:stack.append(node.right)if count == sum_count:sum_count = len(stack)result.append(res)count = 0res = []return result61、序列化二叉樹
請實現兩個函數,分別用來序列化和反序列化二叉樹
解答:
方法:
1、對于序列化:使用前序遍歷,遞歸的將二叉樹的值轉化為字符,并且在每次二叉樹的結點不為空時,在轉化val所得的字符之后添加一個' , '作為分割。對于空節點則以 '#' 代替。
2、對于反序列化:按照前序順序,遞歸的使用字符串中的字符創建一個二叉樹(特別注意:在遞歸時,遞歸函數的參數一定要是char ** ,這樣才能保證每次遞歸后指向字符串的指針會隨著遞歸的進行而移動!!!)
# -*- coding:utf-8 -*- # class TreeNode: # ? ? def __init__(self, x): # ? ? ? ? self.val = x # ? ? ? ? self.left = None # ? ? ? ? self.right = None class Solution:def __init__(self):self.flag = -1 ?def Serialize(self, root):if not root:return '#'return str(root.val) + ',' + self.Serialize(root.left) + ',' + self.Serialize(root.right) ?# write code heredef Deserialize(self, s):self.flag += 1s_list = s.split(',')if self.flag >= len(s_list):return Noneroot = Noneif s_list[self.flag] != '#':root = TreeNode(int(s_list[self.flag]))root.left = self.Deserialize(s)root.right = self.Deserialize(s)return root62、二叉搜索樹的第k個結點
給定一棵二叉搜索樹,請找出其中的第k小的結點。例如,(5,3,7,2,4,6,8)中,按結點數值大小順序第三小結點的值為4。
解答:
方法:
中序遍歷
# -*- coding:utf-8 -*- # class TreeNode: # ? ? def __init__(self, x): # ? ? ? ? self.val = x # ? ? ? ? self.left = None # ? ? ? ? self.right = None class Solution:# 返回對應節點TreeNodedef __init__(self):self.res = [] ?def KthNode(self, pRoot, k):self.Inorder(pRoot)if k == 0 or k > len(self.res) or not pRoot:return Nonereturn self.res[k - 1] ?def Inorder(self, root):if not root:return Noneself.Inorder(root.left)self.res.append(root)self.Inorder(root.right)def KthNode(self, pRoot, k):# write code hereif not pRoot or k == 0:return Nonenode = pRootstack = []res = []while stack or node:while node:stack.append(node)node = node.leftnode = stack.pop()res.append(node)node = node.rightif k > len(res):return Nonereturn res[k-1]63、 數據流中的中位數
如何得到一個數據流中的中位數?如果從數據流中讀出奇數個數值,那么中位數就是所有數值排序之后位于中間的數值。如果從數據流中讀出偶數個數值,那么中位數就是所有數值排序之后中間兩個數的平均值。我們使用Insert()方法讀取數據流,使用GetMedian()方法獲取當前讀取數據的中位數。
解答:
方法:
?
?
# -*- coding:utf-8 -*- class Solution:def __init__(self):self.stack = [] ?def Insert(self, num):# write code hereself.stack.append(num)self.stack.sort() ?def GetMedian(self,stack):# write code hereif len(self.stack) & 1 == 1:return self.stack[len(self.stack)>>1]else:return float(self.stack[len(self.stack)>>1] + self.stack[(len(self.stack)>>1)-1]) / 264、滑動窗口的最大值
給定一個數組和滑動窗口的大小,找出所有滑動窗口里數值的最大值。例如,如果輸入數組{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]}。
解答:
方法:
1、size = 0,返回[]
2、滑動窗口內存儲最大值在num中的index,如果新進隊列的值num[index]大于max_stack[0],則清空max_stack,
3、如果小于max_stack[0],則從后往前刪除比這個數小的數,并將這個數添加到list
4、如果max_stack[0]的值不大于index-size,說明這個值已經劃出窗口,需要pop(0)
# -*- coding:utf-8 -*- class Solution:def maxInWindows(self, num, size):# write code hereif size == 0:return []max_stack = []res = []index = 0while index < len(num):if not max_stack or num[max_stack[0]] < num[index]:del max_stack[:]max_stack.append(index)elif max_stack[0] <= index - size:max_stack.pop(0)max_stack.append(index)else:for i in reversed(range(1, len(max_stack))):if num[max_stack[i]] < num[index]:max_stack.pop(i)max_stack.append(index)if index >= size - 1:res.append(num[max_stack[0]])index += 1return res65、 矩陣中的路徑
請設計一個函數,用來判斷在一個矩陣中是否存在一條包含某字符串所有字符的路徑。路徑可以從矩陣中的任意一個格子開始,每一步可以在矩陣中向左,向右,向上,向下移動一個格子。如果一條路徑經過了矩陣中的某一個格子,則之后不能再次進入這個格子。 例如 a b c e s f c s a d e e 這樣的3 X 4 矩陣中包含一條字符串"bcced"的路徑,但是矩陣中不包含"abcb"路徑,因為字符串的第一個字符b占據了矩陣中的第一行第二個格子之后,路徑不能再次進入該格子。
解答:
方法:
1、根據給定數組,初始化一個標志位數組,初始化為false,表示未走過,true表示已經走過,不能走第二次
2、根據行數和列數,遍歷數組,先找到一個與str字符串的第一個元素相匹配的矩陣元素,進入judge
3、根據i和j先確定一維數組的位置,因為給定的matrix是一個一維數組 /4、確定遞歸終止條件:越界,當前找到的矩陣值不等于數組對應位置的值,已經走過的,這三類情況,都直接false,說明這條路不通
5、若k,就是待判定的字符串str的索引已經判斷到了最后一位,此時說明是匹配成功的
6、下面就是本題的精髓,遞歸不斷地尋找周圍四個格子是否符合條件,只要有一個格子符合條件,就繼續再找這個符合條件的格子的四周是否存在符合條件的格子,直到k到達末尾或者不滿足遞歸條件就停止。
7、走到這一步,說明本次是不成功的,我們要還原一下標志位數組index處的標志位,進入下一輪的判斷。
?
class Solution:def hasPath(self, matrix, rows, cols, path):# write code hereif not path or not matrix or (rows == 0 and cols == 0):return Falseisvisited = [0] * len(matrix)path_lengh = 0for i in range(rows):for j in range(cols):if self.hasPath_part(matrix,rows,cols,i,j,path,path_lengh,isvisited):return Truereturn False ?def hasPath_part(self,matrix,rows,cols,i,j,path,path_length,isvisited):index = i * cols + jif i < 0 or i >= rows or j < 0 or j >= cols or matrix[index] != path[path_length] or isvisited[index] == 1:return Falseif path_length == len(path) - 1:return Trueisvisited[index] = 1if self.hasPath_part(matrix,rows,cols,i+1,j,path,path_length+1,isvisited) \or self.hasPath_part(matrix, rows, cols, i - 1, j, path, path_length + 1, isvisited) \or self.hasPath_part(matrix,rows,cols,i,j+1,path,path_length+1,isvisited) \or self.hasPath_part(matrix,rows,cols,i,j-1,path,path_length+1,isvisited):return Trueisvisited[index] = 0return False ?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 -*- class Solution:def movingCount(self, threshold, rows, cols):# write code hereisvisited = [0] * (rows * cols)count = self.movingCount_part(threshold, rows, cols,0,0,isvisited)return count ? ?def movingCount_part(self, threshold, rows, cols,i,j,isvisited):count = 0if self.check(threshold, rows, cols,i,j,isvisited):isvisited[i*cols+j] = 1count = 1 + self.movingCount_part(threshold, rows, cols,i-1,j,isvisited) \+ self.movingCount_part(threshold, rows, cols,i+1,j,isvisited) \+ self.movingCount_part(threshold, rows, cols,i,j-1,isvisited) \+ self.movingCount_part(threshold, rows, cols,i,j+1,isvisited)return count ? ?def check(self,threshold, rows, cols,i,j,isvisited):if i < 0 or i >= rows or j < 0 or j >= cols \or isvisited[i*cols + j] == 1 \or self.get_num(i) + self.get_num(j) > threshold:return Falsereturn True ? ?def get_num(self,num):sum = 0while num > 0:sum += num % 10num = int(num / 10)return sum總結
以上是生活随笔為你收集整理的牛客网剑指offer编程实践51-66题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: TP-Link TL-WDR4310 无
- 下一篇: 过拟合和欠拟合