因爲以前對算法題接觸很少,所以暫時只作easy和medium難度的題.node
看完了《算法(第四版)》後從新開始刷LeetCode了,此次決定按topic來刷題,有一個大體的方向.有些題不止包含在一個topic中,就以我本身作的前後順序爲準了.python
給定許多條與y軸平行的直線,求其中兩條直線與x軸圍成的容器的最大容量.git
這道題用到了雙指針的思想.咱們在數軸的兩端分別放置一個left指針和right指針,由於容器容量=較短邊*兩邊位置之差,因此若是移動較大的那個指針,那麼容量一定在減少.所以咱們不斷往中間移動較小的指針纔有可能使容量變大,直到兩指針相遇爲止.算法
對於算法合理性的邏輯推理:咱們假設在best_left和best_right位置取到最大容量,那麼left指針到達best_left位置或right指針到達best_right位置至少有一種會發生.不妨令left指針到達best_left位置,此時right指針的位置有三種可能:segmentfault
class Solution(object): def maxArea(self, height): """ :type height: List[int] :rtype: int """ left = 0 right = len(height) - 1 most = 0 while left != right: h = min(height[left], height[right]) most = max(most, h * (right - left)) if height[left] < height[right]: left += 1 else: right -=1 return most Container With Most Water
給定一個數組和一個目標值,找到數組中的三個數,使得這三個數之和與目標值之間的差距最小,返回它們的和.數組
這題的思路與15題相似,也是利用雙指針,只不過斷定條件從三個數之和是否爲零改爲了三個數之和是否比目前已有的closest值更接近目標.app
class Solution: def threeSumClosest(self, nums, target): """ :type nums: List[int] :type target: int :rtype: int """ closest = nums[0] + nums[1] + nums[2] nums.sort() length = len(nums) for i in range(length): l = i + 1 r = length - 1 while l < r: tmp = nums[i] + nums[l] + nums[r] if tmp == target: closest = target break elif tmp < target: if target - tmp < abs(target - closest): closest = tmp l += 1 elif tmp > target: if tmp - target < abs(target - closest): closest = tmp r -= 1 return closest 3Sum Closest
找出list中全部相加等於target的4個數的list.ide
一開始個人思路是令new_target=target-num1,而後轉換爲一個3Sum問題,但這種作法的時間複雜度過高了.查看Solution後發現這道題要使用hash的思想,在python中對應的實現就是使用先dict存儲list中的兩數之和和它們在list中的位置,而後對於這個dict中的value,尋找一個key=target-value,而後將他們對應的數字存入list便可.須要注意的是python中的list,set,dict是不可哈希的,int,float,str,tuple是可哈希的.函數
class Solution: def fourSum(self, nums, target): """ :type nums: List[int] :type target: int :rtype: List[List[int]] """ d = dict() for i in range(len(nums)): for j in range(i+1,len(nums)): sum2 = nums[i]+nums[j] if sum2 in d: d[sum2].append((i,j)) else: d[sum2] = [(i,j)] result = [] for key in d: value = target - key if value in d: list1 = d[key] list2 = d[value] for (i,j) in list1: for (k,l) in list2: if i!=k and i!=l and j!=k and j!=l: flist = [nums[i],nums[j],nums[k],nums[l]] flist.sort() if flist not in result: result.append(flist) return result
給定一個有序list和一個數target,求這個數在這個list中的位置.post
有序,立刻想到了二分查找,只不過要針對找不到的狀況進行一下特殊處理.普通的二分查找在找不到時返回的是-1,咱們這裏只要返回找不到時傳入函數的left就好了.
class Solution: def searchInsert(self, nums, target): """ :type nums: List[int] :type target: int :rtype: int """ def bs(numlsit, l, r): while l <= r: mid = int((l + r) / 2) if numlsit[mid] == target: return mid elif numlsit[mid] < target: return bs(numlsit, mid+1, r) else: return bs(numlsit, l, mid-1) return l return bs(nums, 0, len(nums)-1)
給定一個無序list,求出其中缺失的最小正整數,要求時間複雜度O(n).
設list長度爲l的話,最後的答案確定是1~l+1之間的一個正整數,因此想到了設置標誌數組flag,flag[i]爲1表示i+1已經出現過了.遍歷一次list後再遍歷一次flag,遇到的第一個0的index就是答案.若是遍歷完整個flag都沒有輸出值,說明答案是l+1.
class Solution: def firstMissingPositive(self, nums): """ :type nums: List[int] :rtype: int """ if nums == []: return 1 l = len(nums) pi = [0] * l for i in range(l): tmp = nums[i] if tmp > 0 and tmp <= l: pi[tmp-1] = 1 for i in range(l): if pi[i] == 0: return i+1 return l+1
給定一個非負整數list,初始位置在list[0],list的值表明了該位置能向前走的最大步數,求走到list末尾所需的最小次數(假設必定可以走到末尾).
既然要求最小次數,那麼目的就是每一步都儘量地往前走.這裏的"儘量"並不是是每一步都走能走的最大步數,而是走到的位置加上該位置的最大步數,這表明了咱們下一步的選擇範圍.理清這一點後代碼就很簡單了.
class Solution: def jump(self, nums): """ :type nums: List[int] :rtype: int """ l = len(nums) pos = 0 sum = 0 def find_next(pos): next = 0 pace = nums[pos] max = 0 if pos + pace >= l - 1: next = l - 1 else: for i in range(1, pace+1): tmp = i + nums[pos+i] if tmp > max: max = tmp next = pos + i return next while pos < l - 1: pos = find_next(pos) sum += 1 return sum
給定一個非負整數list,初始位置在list[0],list的值表明了該位置能向前走的最大步數,求是否能走到list末尾.
這道題和45題相似,咱們仍然採用45題的走法,可是加入一個斷定條件,若是走到了list[i]=0的位置說明不可以走到終點,輸出False,不然輸出True.
class Solution: def canJump(self, nums): """ :type nums: List[int] :rtype: bool """ l = len(nums) pos = 0 sum = 0 def find_next(pos): next = 0 pace = nums[pos] max = 0 if pos + pace >= l - 1: next = l - 1 else: for i in range(1, pace + 1): tmp = i + nums[pos + i] if tmp > max: max = tmp next = pos + i return next while pos < l - 1: if nums[pos] == 0: return False pos = find_next(pos) sum += 1 return True
給定一個正整數n,生成一個n*n的矩陣,其中元素按照螺旋形從1一直到n^2
觀察這個生成的矩陣,會發現每一圈都是從左上角開始,沿着順時針方向遞增的規律生成的.按照這個思路,咱們定義一個circle函數,它每次都在n*n的矩陣中生成一圈符合條件的數.這個函數接受三個參數,分別表明了出發點,邊長還有初始值.其中出發點從(0,0)開始,每次增長(1,1),邊長從n開始每次-2,初始值能夠經過函數中加入數字的次數獲得.
class Solution: def generateMatrix(self, n): """ :type n: int :rtype: List[List[int]] """ spiral = [[0 for i in range(n)] for j in range(n)] def circle(start, length, initial): sum = 0 for i in range(length): spiral[start][start+i] = i + 1 + initial sum += 1 for i in range(length-1): spiral[start+i+1][start+length-1] = i + length + 1 + initial sum += 1 for i in range(length-1): spiral[start+length-1][start+length-i-2] = i + 2 * length + initial sum +=1 for i in range(length-2): spiral[start+length-i-2][start] = i + 3 * length - 1 + initial sum += 1 return sum times = int((n+1)/2) sum = 0 for i in range(times): sum += circle(i, n-2*i, sum) return spiral
給定一個m*n的矩陣,其中0表明能夠走的路,1表明障礙物.機器人只能往下或往右走,初始位置在矩陣左上角,求可讓機器人走到矩陣右下角的路徑的數量.
一開始想用深度優先遍歷解決,後來發現太費時間,因而想到了動態規劃.公式以下:
class Solution: def uniquePathsWithObstacles(self, obstacleGrid): """ :type obstacleGrid: List[List[int]] :rtype: int """ m = len(obstacleGrid) n = len(obstacleGrid[0]) dp = [[0 for i in range(n)] for j in range(m)] dp[0][0] = 0 if obstacleGrid[0][0] == 1 else 1 for i in range(m): for j in range(n): if obstacleGrid[i][j] == 1: dp[i][j] == 0 else: if i-1 >= 0: dp[i][j] += dp[i-1][j] if j-1 >= 0: dp[i][j] += dp[i][j-1] return dp[m-1][n-1]
給定一個m*n的非負矩陣,矩陣中的數字表明權值,起點在矩陣左上角,只能往右或往下走,求走到矩陣右下角所需的最小路徑長度.
基本的動態規劃題,dp[0][0]=grid[0][0],dp[i][j]=grid[i][j]+min(dp[i-1][j],dp[i][j-1]),第一排和第一列因爲沒有上/左的格子,須要提早處理.
class Solution: def minPathSum(self, grid): """ :type grid: List[List[int]] :rtype: int """ m = len(grid) n = len(grid[0]) dp = [[0 for i in range(n)] for j in range(m)] dp[0][0] = grid[0][0] for i in range(1,n): dp[0][i] = grid[0][i] + dp[0][i-1] for i in range(1,m): dp[i][0] = grid[i][0] + dp[i-1][0] for i in range(1, m): for j in range(1, n): dp[i][j] = grid[i][j] + min(dp[i-1][j], dp[i][j-1]) return dp[-1][-1]
給定一個非空的個位數數組,這個數組總體表明瞭一個非負整數.將這個非負整數+1後用個位數數組的形式返回.
思路比較簡單,就是將數組中的數分別取出乘上位數後相加,再將這個數+1後存入另外一個數組.值得注意的是python雖然支持大數運算,但若是超出了2^63-1的範圍後用int()類型轉換會丟失一部分值,因此要在運算過程當中轉換爲字符串來處理.
class Solution: def plusOne(self, digits): """ :type digits: List[int] :rtype: List[int] """ plus = [] sum = 0 l = len(digits) for i in range(l): sum *= 10 sum += digits[i] sum += 1 while sum != '' and sum > 0: plus.insert(0,sum%10) sum = str(sum)[:-1] if sum != '': sum = int(sum) return plus
提交事後雖然AC了,可是運算速度較慢,查看了Solution後發現這題應該用加法器的思想來作,有進位則本位置0,保留進位.
class Solution: def plusOne(self, digits): """ :type digits: List[int] :rtype: List[int] """ p = 1 for i in range(len(digits), 0 , -1): r = digits[i-1] + p if r >= 10: p = 1 digits[i-1] = 0 else: p = 0 digits[i-1] = r if p == 1: digits = [1] + digits return digits
給定一個m*n的矩陣matrix,若是有一個元素是0,則將該元素的所在行和列都變爲0.要求in-palce就地操做實現,也就是不使用臨時變量,空間複雜度O(1).
空間複雜度O(MN)的解法:新建一個m*n的矩陣,掃描matrix,掃到0就在新矩陣對應行和列賦0,最後把新矩陣賦給matrix
空間複雜度O(M+N)的解法:新建一個長度爲M的數組記錄每一行是否有0,一個長度爲N的數組記錄每一列是否有0
空間複雜度O(1)的解法:利用matrix自己記錄,首先定義row_flag和column_flag表示矩陣的第一行和第一列是否有0,而後掃描矩陣除了第一行和第一列之外的部分,用第一行和第一列置0來表示有0.
class Solution: def setZeroes(self, matrix): """ :type matrix: List[List[int]] :rtype: void Do not return anything, modify matrix in-place instead. """ m = len(matrix) n = len(matrix[0]) row_flag = False col_flag = False for i in range(n): if matrix[0][i] == 0: row_flag = True for i in range(m): if matrix[i][0] == 0: col_flag = True for i in range(1,m): for j in range(1,n): if matrix[i][j] == 0: matrix[i][0] = 0 matrix[0][j] = 0 for i in range(1,m): for j in range(1,n): if matrix[i][0] == 0 or matrix[0][j] == 0: matrix[i][j] = 0 if row_flag: for i in range(n): matrix[0][i] = 0 if col_flag: for i in range(m): matrix[i][0] = 0
給定一個m*n的整數矩陣,其中每行數從左到右升序排列,而且知足每行的第一個數大於上一行的最後一個數,給定一個target,肯定target是否在這個矩陣中.
看見有序仍是先想到二分查找,由於每一行之間實際也隱含着順序了,因此只要先根據每一行的最後一個數判斷出咱們想要查找的是哪一行,而後對那一行進行二分查找便可.注意[]和[[]]的特殊狀況.
class Solution: def searchMatrix(self, matrix, target): """ :type matrix: List[List[int]] :type target: int :rtype: bool """ def binary_search(numlist, l, r, t): while l <= r: mid = int((l + r) / 2) if numlist[mid] == t: return True elif numlist[mid] < t: return binary_search(numlist, mid+1, r, t) else: return binary_search(numlist, l, mid-1, t) return False if matrix == [] or matrix == [[]]: return False if target < matrix[0][0] or target > matrix[-1][-1]: return False m = len(matrix) n = len(matrix[0]) for i in range(m): if matrix[i][-1] >= target: return binary_search(matrix[i], 0, n-1, target)
給定一個不含重複元素的數組,返回該數組可能的全部子集
一開始想到用遞歸來作,在list中記錄s,而後遍歷s中的每一個元素i,使用s-i來遞歸,可是隻要數組元素稍微多一點就超時,顯然是時間複雜度過高了.
查閱資料後發現這道題應該用回溯法+深度優先遍歷,以[1,2,3]爲例,第一層元素爲[],第二層元素爲[1],[2],[3],每深刻一層就要刪除剛剛加入的元素,直到數組裏的元素所有用完後再回溯:
class Solution: def subsets(self, nums): """ :type nums: List[int] :rtype: List[List[int]] """ l = [[]] def dfs(nums, index, path, li): for i in range(index, len(nums)): li.append(path+[nums[i]]) path.append(nums[i]) dfs(nums, i+1, path, li) path.pop() if nums is None: return [] dfs(nums, 0, [], l) return l
給定一個二維list和一個word,判斷這個word是否能用二維list中相鄰的字母鏈接而成(不能重複使用)
一道dfs題目,終止條件是當全部字母找完時返回True,當沒找完而且四個方向都不能繼續走下去時返回False.找到一個字母后分別向四個方向走,若是其中一個方向返回True則總體爲True.走過的位置設爲'#',當四個方向都回來後將'#'從新變回原來的字母.
class Solution: def exist(self, board, word): """ :type board: List[List[str]] :type word: str :rtype: bool """ m = len(board) n = len(board[0]) l = len(word) def near(grid, i, j, word, pos): if pos == l: return True if i-1 < -1 or i+1 > m or j-1 < -1 or j+1 > n or word[pos] != grid[i][j]: return False tmp = board[i][j] board[i][j] = '#' res = near(grid, i+1, j, word, pos+1) or near(grid, i-1, j, word, pos+1)\ or near(grid, i, j+1, word, pos+1) or near(grid, i, j-1, word, pos+1) board[i][j] = tmp return res for i in range(m): for j in range(n): if near(board, i, j, word, 0): return True return False
給定一個有序list,使得其中的數字不能重複出現兩次以上,要求in-place作法,返回值爲處理後的數組的長度
由於要求in-place,因此先用一個for循環找出重複兩次以上的數字的位置,將它們改成'#',而後在第二次for循環刪去這些'#'.注意這一次的循環要用倒序,不然會由於刪去元素致使索引不正確而出錯.
class Solution: def removeDuplicates(self, nums): """ :type nums: List[int] :rtype: int """ if nums == []: return 0 l = len(nums) dup = 0 tmp = nums[0] for i in range(1,l): if nums[i] == tmp: dup += 1 else: dup = 0 tmp = nums[i] if dup >= 2: nums[i] = '#' for i in range(l-1, -1, -1): if nums[i] == '#': nums.pop(i) return len(nums)
給定一個list,是由一個有序數組在某一樞紐處旋轉獲得的,而且其中可能含有重複元素,要求判斷target是否在這個list中.
雖然這個list通過旋轉,可是仍是能夠用二分查找的思想,由於mid的左邊或右邊必定有一端是有序的.所以只須要在二分查找的時候對此進行判斷就好了.另外本題可能有重複值,因此當left,mid和right指向的值都相等時要移動指針來跳出循環.
class Solution: def search(self, nums, target): """ :type nums: List[int] :type target: int :rtype: bool """ left = 0 right = len(nums)-1 while left <= right: mid = int((left + right) / 2) if nums[mid] == target: return True if nums[mid] < nums[right] or nums[mid] < nums[left]: if nums[mid] < target <= nums[right]: left = mid + 1 else: right = mid - 1 elif nums[mid] > nums[left] or nums[mid] > nums[right]: if nums[mid] > target >= nums[left]: right = mid - 1 else: left = mid + 1 else: left += 1 return False
給定二叉樹的前序遍歷和中序遍歷,輸出該二叉樹
前序遍歷也就是根-左-右,中序遍歷就是左-根-右.咱們用遞歸的方式,preorder[0]一定是根結點,而這個根結點在inorder中的位置的左邊是它的左子樹,右邊是它的右子樹.只要抓住這個關鍵點就能夠了.
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def buildTree(self, preorder, inorder): """ :type preorder: List[int] :type inorder: List[int] :rtype: TreeNode """ if len(preorder) == 0:return None root_node = TreeNode(preorder[0]) j = inorder.index(preorder[0]) root_node.left = self.buildTree(preorder[1:j+1],inorder[0:j]) root_node.right = self.buildTree(preorder[j+1:],inorder[j+1:]) return root_node
給定二叉樹的中序遍歷和後序遍歷,輸出該二叉樹
中序遍歷是左-根-右,後序遍歷是左-右-根.preorder[-1]一定是根結點.而後就和105題相似了.
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def buildTree(self, inorder, postorder): """ :type inorder: List[int] :type postorder: List[int] :rtype: TreeNode """ if len(postorder) == 0:return None root_node = TreeNode(postorder[-1]) j = inorder.index(postorder[-1]) root_node.left = self.buildTree(inorder[0:j], postorder[0:j]) root_node.right = self.buildTree(inorder[j+1:],postorder[j:-1]) return root_node
楊輝三角問題,給定k,要求輸出楊輝三角的第k行
雖然看似是等腰三角形,但其實咱們能夠把它看作一個直角三角形,也就是矩陣的下半部分.這題若是用O(k^2)的空間的話很是簡單,抓住t[i][j] = t[i-1][j]+t[i-1][j-1]便可.題幹給了一個挑戰,是用O(k)的空間完成,其實也很是簡單,只要設置兩個臨時變量,分別存儲咱們要修改的位置的上一層的這一位和前一位便可(邏輯上的上層,實際上只有一維數組).
class Solution: def getRow(self, rowIndex): """ :type rowIndex: int :rtype: List[int] """ size = rowIndex+1 tri = [0] * size tri[0] = 1 for i in range(1,size): t1 = 1 for j in range(1,size): t2 = tri[j] tri[j] = tri[j] + t1 t1 = t2 return tri
給定一個三角形的list,求出從頂到底的最短路徑.
經典DP題,很是簡單.DP算式爲 tri[n-1][i] += min(tri[n][i], tri[n][i+1])
class Solution: def minimumTotal(self, triangle): """ :type triangle: List[List[int]] :rtype: int """ def dp(tri, n): if n < 1: return for i in range(n): tri[n-1][i] += min(tri[n][i], tri[n][i+1]) dp(tri, n-1) dp(triangle, len(triangle)-1) return triangle[0][0]
給定一個list,找出其中一個連續的子數組,使得其中全部數的乘積最大.
首先對整個數組求積,若是大於0則這就是答案,若是小於0則遍歷數組,若是找到0則對0左右的數組重複上述操做,若是找到負數則求負數兩邊的乘積之和.
class Solution: def maxProduct(self, nums): """ :type nums: List[int] :rtype: int """ def product(nums): if len(nums) == 0: return 0 s = 1 for x in nums: s *= x return s def find_max(nums): pro = product(nums) if pro > 0: return pro else: for i in range(len(nums)): if nums[i] == 0: return max(0, find_max(nums[:i]), find_max(nums[i+1:])) if nums[i] < 0: if len(nums[:i]) > 0: pro_left = product(nums[:i]) else: pro_left = pro if len(nums[i+1:]) > 0: pro_right = product(nums[i+1:]) else: pro_right = pro pro = max(pro, pro_left, pro_right) return pro if len(nums) == 1: return nums[0] pro = find_max(nums) return pro
給定一個排序過的list,在某一結點旋轉過,找出其中的最小值
相似81題,仍是用二分查找的思想.雖然list被旋轉過,可是left-mid和mid-right其中的一段一定是有序的.
class Solution: def findMin(self, nums): """ :type nums: List[int] :rtype: int """ l = len(nums) left = 0 right = l-1 mid = (left+right)//2 while left < right: if nums[right] < nums[mid]: left = mid+1 else: right = mid mid = (left+right)//2 return min(nums[left], nums[right])
給定一個排序過的list,從中找到和等於target的兩個數的位置,返回它們以1爲起始值的座標.
雙指針的思想,比較簡單.值得一提的是,若是須要從無序數組中找到是否有兩數之和等於某一target,也是採用先排序再雙指針的方法.
class Solution: def twoSum(self, numbers, target): """ :type numbers: List[int] :type target: int :rtype: List[int] """ l = 0 r = len(numbers) - 1 while l < r: if numbers[l] + numbers[r] > target: r -= 1 elif numbers[l] + numbers[r] < target: l += 1 else: break ans = [l+1, r+1] return ans
給定一個list和一個k,使這個list旋轉k步
利用python的切片便可
class Solution: def rotate(self, nums, k): """ :type nums: List[int] :type k: int :rtype: void Do not return anything, modify nums in-place instead. """ l = len(nums) k = k % l nums[:] = nums[l-k:] + nums[:l-k]
給定一個list和一個正數s,找到list中和大於等於s的最小連續區間的長度.若是沒有則返回0.
個人思路是雙指針法,用一個滑動的窗口去匹配,若是窗口內的值大於等於s則左移左邊框,不然右移右邊框,直到右邊框到達數組底部而且窗口值小於s位置.
class Solution: def minSubArrayLen(self, s, nums): """ :type s: int :type nums: List[int] :rtype: int """ if sum(nums) < s: return 0 elif max(nums) >= s: return 1 l, r = 0, 1 add = nums[0] + nums[1] minimum = len(nums) while l < len(nums): if add >= s: tmp = r-l+1 minimum = min(minimum, tmp) add -= nums[l] l += 1 else: if r < len(nums)-1: r += 1 add += nums[r] else: break return minimum
給定一個數k和一個數n,要求找到1-9內的k個數,且知足它們的和爲n的全部可能組合.
這道題是回溯法的應用.回溯法至關於有剪枝的DFS.思路是:保存當前步驟,若是是一個解就輸出;維護狀態,使搜索路徑(含子路徑)儘可能不重複.必要時,應該對不可能爲解的部分進行剪枝.
代入到這題中,每個dfs都遍歷1-9中當前index後面的數,這確保了已經拿過的數再也不拿.進入下一層dfs,並令k-1,n-nums[index],跳出條件是k<0或n<0,知足條件是k==0且n==0.
class Solution: def combinationSum3(self, k, n): """ :type k: int :type n: int :rtype: List[List[int]] """ nums = [1,2,3,4,5,6,7,8,9] res = [] def dfs(nums, k, n, index, path, res): if k < 0 or n < 0: return if k == 0 and n == 0: res.append(path) for i in range(index, len(nums)): dfs(nums, k-1, n-nums[i], i+1, path+[nums[i]], res) dfs(nums, k, n, 0, [], res) return res
給定一個有序且無重複數字的list,將其中連續範圍的數字合併後返回
根據題意,咱們須要確認的其實就是每段連續區間的首尾數字.首數字多是list的第一個數或是前一個數和它不連續的數,尾數字多是list的最後一個數或是後一個數和它不連續的數.而且每個尾數字必定對應着一段連續區間,將這段區間存入一個字符list便可.
class Solution: def summaryRanges(self, nums): """ :type nums: List[int] :rtype: List[str] """ summary = [] start = 0 end = 0 for i in range(len(nums)): if i == 0 or nums[i-1]+1 != nums[i]: start = nums[i] if i == len(nums)-1 or nums[i+1]-1 != nums[i]: end = nums[i] if start == end: summary.append(str(start)) else: summary.append(str(start)+'->'+str(end)) return summary
給定一個長度爲n的list,找到其中出現次數大於[n/3]的全部數.要求時間複雜度O(n),空間複雜度O(1).
個人想法是使用dict存儲這個list中每一個數出現的次數,而後將其中次數大於[n/3]的存入一個list.可是則不符合空間複雜度的要求.
查閱solution後發現這題可使用Boyer-Moore多數投票算法解決.這是一種尋找"多數元素"的好方法,基本思想是創建標誌位和count,若是匹配到的數字不等於標誌位則讓count-1,不然count+1,若是count爲0時更換標誌位.由於本題要求的是出現次數大於[n/3]的全部數,也就是最多可能有兩個數,所以要創建兩組標誌位和count.
class Solution: def majorityElement(self, nums): """ :type nums: List[int] :rtype: List[int] """ count1, count2, tmp1, tmp2 = 0, 0, 0, 1 for i in nums: if i == tmp1: count1 += 1 elif i == tmp2: count2 += 1 elif count1 == 0: tmp1 = i count1 = 1 elif count2 == 0: tmp2 = i count2 = 1 else: count1 -= 1 count2 -= 1 ans = [n for n in (tmp1, tmp2) if nums.count(n) > len(nums) // 3] return ans
給定一個list,將其中全部的0移到末尾,而且保持其餘元素的順序不變.要求in-place完成.
若是咱們採用的是交換位置或是移動0的話,index的變化將很是繁瑣.因此咱們將思路放在非零元素上:老是將非零元素與第一個零元素交換位置,每一次交換後將對應第一個零元素的index+1便可.
給定一個數字n,生成全部存儲了1~n的二叉查找樹的可能形式.
這題的思路是每次選取一個結點做爲根,而後根據這個根把樹切分爲左右兩個子樹,再在左右兩個子樹裏選取結點做爲根,直至子樹爲空.注意子樹爲空時要返回[None]而不是[],不然循環沒法進行.
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def generateTrees(self, n): """ :type n: int :rtype: List[TreeNode] """ def dfs(nums): if not nums: return [None] result = [] for i in range(len(nums)): for l in dfs(nums[:i]): for r in dfs(nums[i+1:]): node = TreeNode(nums[i]) node.left, node.right = l, r result.append(node) return result nums = list(range(1,n+1)) if n == 0: return [] return dfs(nums)
給定一個list,表明一條街道上每棟房子裏的財物.咱們要儘量多地搶這些財物,可是不能搶相鄰的兩棟房子.
遞推式是:
class Solution: def rob(self, nums): """ :type nums: List[int] :rtype: int """ if not nums: return 0 elif len(nums) == 1: return nums[0] else: nums[1] = max(nums[0], nums[1]) for i in range(2,len(nums)): nums[i] = max(nums[i]+nums[i-2], nums[i-1]) return nums[-1]
給定一個list,表明一條街道上每棟房子裏的財物.咱們要儘量多地搶這些財物,可是不能搶相鄰的兩棟房子.這個街道是環形的.
這題和198很像,區別只是增長了一個第一棟房子與最後一棟房子不能同時搶的斷定.因此咱們分爲兩種狀況,同時爲了節省空間,採用了臨時變量:
class Solution: def rob(self, nums): """ :type nums: List[int] :rtype: int """ if not nums: return 0 elif len(nums) < 4: return max(nums) else: pplast, plast = 0, 0 for i in nums[:-1]: tmp = plast plast = max(pplast+i, plast) pplast = tmp result = plast pplast, plast = 0, 0 for i in nums[1:]: tmp = plast plast = max(pplast+i, plast) pplast = tmp return max(result, plast)
找到第n個ugly number(質因數只有2,3,5的數字,包括1)
由於ugly number的質因數只有3種可能性,因此每個ugly number必定是由另外一個ugly number乘上這三個數的其中之一獲得的(1除外).因此想到了設立3個標誌位,分別表明2,3,5的乘數在數組中的位置,判斷它們的乘積最小者就是下一個ugly number.
class Solution: def nthUglyNumber(self, n): """ :type n: int :rtype: int """ ugly = [1] tmp_2, tmp_3, tmp_5 = 0, 0, 0 for i in range(1,n): tmp = min(2*ugly[tmp_2], 3*ugly[tmp_3], 5*ugly[tmp_5]) if tmp == 2*ugly[tmp_2]: tmp_2 += 1 if tmp == 3*ugly[tmp_3]: tmp_3 += 1 if tmp == 5*ugly[tmp_5]: tmp_5 += 1 ugly.append(tmp) return ugly[-1]
給定一個正整數n,找到相加之和等於它所需的徹底平方數的最小個數.
只要找到表達式dp[i]=min(dp[i],dp[i-j*j])就能夠了.
class Solution: def numSquares(self, n): """ :type n: int :rtype: int """ if n == 0: return 0 dp = list(range(0,n+1)) dp[1] = 1 for i in range(1,n+1): j = 1 while j*j <= i: dp[i] = min(dp[i], dp[i-j*j]+1) j += 1 return dp[-1]
給定一個無序list,找出其中最長的遞增子序列
dp的思路是比較容易想到的,使用一個dp數組存儲該位置的遞增子序列長度,dp[0]=1,對於i,遍歷全部小於i的j,只要nums[j]<nums[i],就使用表達式dp[i]=max(dp[i], dp[j]+1)來更新dp數組. 時間複雜度是O(n^2)
class Solution: def lengthOfLIS(self, nums): """ :type nums: List[int] :rtype: int """ l = len(nums) if l < 2: return l dp = [1 for i in range(l)] for i in range(l): tmp = nums[i] for j in range(i): if nums[j] < tmp: dp[i] = max(dp[i], dp[j]+1) return max(dp)
另外一種在評論區看到的思路是使用一個tails數組,它的第i位表明的是nums中長度爲i的遞增子序列的最小數值.易得tails是一個遞增數組.而後對於每個數x,若是它比tails[-1]大,就在tails數組中增長一位,若是它知足tails[i-1] < x <= tails[i],就更新tails[i]=x.這樣作的好處是能夠用二分查找來肯定x的位置.這種作法的時間複雜度是O(nlogn)
def lengthOfLIS(self, nums): tails = [0] * len(nums) size = 0 for x in nums: i, j = 0, size while i != j: m = (i + j) / 2 if tails[m] < x: i = m + 1 else: j = m tails[i] = x size = max(i + 1, size) return size
給定一個list表明股票價格,要求賣完股票後的第一天不能買入股票,求買賣能夠產生的最大利潤.
一開始沒有思路,在discuss看到這實際上是一道狀態轉移的問題.總共有hold,notHold,cooldown三種狀態,它們之間的轉移方程以下:
初始狀態是notHold,而後只要遍歷prices的list便可.
class Solution: def maxProfit(self, prices): """ :type prices: List[int] :rtype: int """ hold = float('-inf') notHold = 0 cooldown = float('-inf') for p in prices: hold = max(hold, notHold-p) notHold = max(notHold, cooldown) cooldown = hold+p return max(notHold, hold, cooldown)
給定一個list表明不一樣面值的錢,和一個總數amount,求出能湊出amount所需的錢的最小數量,若是湊不齊則返回-1.
找到表達式dp[i]=min(dp[i-coin]+1),注意湊不齊的金額設爲float('inf')便可.
class Solution: def coinChange(self, coins, amount): """ :type coins: List[int] :type amount: int :rtype: int """ MAX = float('inf') dp = [0] + [MAX] * amount for i in range(1, amount + 1): dp[i] = min([dp[i - c] if i - c >= 0 else MAX for c in coins]) + 1 return [dp[amount], -1][dp[amount] == MAX]
給定一個非負整數num,對於0<=i<=num,返回一個list,表明i的二進制表示中1的數量.
只有0對應的二進制的1的數量是0,對於任意的正整數num,均可以寫成num = 2**i + k(k<num/2)的形式,若是k=0時對應的1的數量爲1,不然就是1+dp[k].由於k<2**i,因此咱們能夠確保dp[k]必定已經存過數字.
class Solution: def countBits(self, num): """ :type num: int :rtype: List[int] """ dp = [0] * (num+1) carry = 1 for i in range(1, num + 1): if carry*2 == i: carry = i dp[i] = 1+dp[i-carry] return dp
給定一個正整數n,將它拆分紅至少兩個數字的和,使得這些數字之積最大.
我想到的是dp的作法,dp[n]爲n對應的最大積,那麼dp[2]=1,dp[n]=max(i*dp[n-i],i*(n-i))
class Solution: def integerBreak(self, n): """ :type n: int :rtype: int """ dp = [0]*(n+1) dp[0] = 1 dp[1] = 1 for i in range(n+1): for j in range(i): dp[i] = max(dp[i], j*(i-j), j*dp[i-j]) return dp[-1]
實際上這題經過數學推導,能夠發現最好的就是將數字三等分,若是不行就二等分,這樣就能夠很快求解了.
給定一棵二叉樹,返回它的中序遍歷結果.
遞歸,若是root爲空則返回,不然遞歸遍歷左結點,存入根結點,遞歸遍歷右結點.
若是不用遞歸的話,能夠採用棧來實現,也就是結點非空時就將根結點存入棧,而後進入左結點,直到結點爲空時,從棧中彈出第一個結點加入res[],而後訪問該結點的右結點.
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def inorderTraversal(self, root): """ :type root: TreeNode :rtype: List[int] """ node = [] def it(root): if root == None: return else: it(root.left) node.append(root.val) it(root.right) it(root) return node
給定兩棵二叉樹,判斷它們是否相同.
遞歸,若是p與q都存在的話,返回對p與q的val是否相等的判斷結果and對p.left和q.left的判斷結果and對p.right和q.right的判斷結果.若是p與q不存在的話,則用p==q判斷是否二者都爲None.這裏用到的技巧是True and False = Flase.
這題也能夠用棧來實現.
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def isSameTree(self, p, q): """ :type p: TreeNode :type q: TreeNode :rtype: bool """ if p and q: return p.val == q.val and self.isSameTree(p.left, q.left) and self.isSameTree(p.right, q.right) else: return p == q
給定一棵二叉樹,返回它的zigzag遍歷結果.(也就是同一層從左到右,下一層再從右到左,如此循環)
個人方法是設立標誌位i表明第i層,若是結點存在,且res數組的長度小於i,就在res數組中加入一個[],而後將這個結點的值存入,並遞歸左結點和i+1,而後遞歸右結點和i+1.最後再將res中的偶數list作reverse操做.
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def zigzagLevelOrder(self, root): """ :type root: TreeNode :rtype: List[List[int]] """ res = [] def helper(root, i): if root: if len(res) < i: res.append([]) res[i-1].append(root.val) helper(root.left, i+1) helper(root.right, i+1) helper(root,1) for i in range(len(res)): if i % 2 != 0: res[i].reverse() return res
給定一棵二叉樹,返回它自底向上,從左到右的遍歷結果.
與103題相似,只不過最後是對整個res作reverse操做.
若是不用遞歸的話,還能夠用dfs+棧或bfs+隊列.
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def levelOrderBottom(self, root): """ :type root: TreeNode :rtype: List[List[int]] """ res = [] def helper(root, i): if root: if len(res) < i: res.append([]) res[i-1].append(root.val) helper(root.left, i+1) helper(root.right, i+1) helper(root,1) res.reverse() return res
給定一棵二叉樹,判斷它是否是一棵平衡二叉樹.
平衡二叉樹的定義:要麼是一棵空樹,要麼左右子樹都是平衡二叉樹,而且左右子樹的深度之差的絕對值不超過1.
若是採用求深度的方法,那麼部分結點會被重複訪問不少次,因此想到了後序遍歷,它的特色是訪問到根結點時,根結點對應的左結點和右結點都已經被訪問過了.若是在訪問過程當中發現左結點和右結點的深度之差大於1,就返回-1,同理若是左結點和右結點的返回值已是-1了,也返回-1,否則就返回1+左結點和右結點的較大值.
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def isBalanced(self, root): """ :type root: TreeNode :rtype: bool """ def helper(root): if not root: return 0 left = helper(root.left) right = helper(root.right) if left == -1 or right == -1 or abs(left-right) > 1: return -1 return 1 + max(left, right) return helper(root) != -1
給定一棵二叉樹,返回它的最小深度
遞歸解決,對於一棵二叉樹的每個結點,若是它同時有左右子樹,那麼深度爲1+min(left,right),不然深度爲另外一個子樹的最小深度+1.
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def minDepth(self, root): """ :type root: TreeNode :rtype: int """ if not root: return 0 if not root.left: return 1 + self.minDepth(root.right) elif not root.right: return 1 + self.minDepth(root.left) else: return 1 + min(self.minDepth(root.left), self.minDepth(root.right))
給定一棵二叉樹和一個sum,判斷二叉樹中是否有一條從根結點到葉子結點的路徑,使得結點之和等於sum.
比較簡單,使用一個輔助值tmp記錄路徑的和,若是爲葉子結點且路徑和加上值等於sum則返回True,不然返回helper(root.left) or helper(root.right)
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def hasPathSum(self, root, sum): """ :type root: TreeNode :type sum: int :rtype: bool """ def helper(root, sum, tmp): if not root: return False tmp += root.val if not root.left and not root.right and tmp == sum: return True else: return helper(root.left, sum, tmp) or helper(root.right, sum, tmp) return helper(root, sum, 0)
給定一棵二叉樹和一個sum,找出全部知足和等於sum的根結點到葉子結點的路徑.
思路和112題大致一致,只不過須要在函數中加入兩個list參數,一個存儲路徑,最後若是判斷等於sum就加入到另外一箇中做爲最後結果.
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def pathSum(self, root, sum): """ :type root: TreeNode :type sum: int :rtype: List[List[int]] """ def dfs(root, sum, ls, res): if not root.left and not root.right and sum == root.val: ls.append(root.val) res.append(ls) if root.left: dfs(root.left, sum-root.val, ls+[root.val], res) if root.right: dfs(root.right, sum-root.val, ls+[root.val], res) if not root: return [] res = [] dfs(root, sum, [], res) return res
給定一棵二叉樹,將它變爲鏈表,要求in-place操做
在對根結點操做時,若是已經將它的左右子樹都拉平過,就將左子樹加入到根結點和右子樹中間,因此採用後序遍歷順序來遞歸.
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def flatten(self, root): if not root: return if root.left: self.flatten(root.left) if root.right: self.flatten(root.right) left = root.left right = root.left while right and right.right: right = right.right if right: right.right = root.right if left: root.right = left root.left = None
給定一棵二叉樹,每個結點都是0-9中的一位數字,求全部根結點到葉子結點的路徑上的數字之和.
遞歸,每深刻一個結點就讓當前的值*10傳下去,直到葉子結點後將值存入一個list,最後對該ist求和便可.
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def sumNumbers(self, root): """ :type root: TreeNode :rtype: int """ def helper(root, value, res): if root: helper(root.left, root.val+value*10, res) helper(root.right, root.val+value*10, res) if not root.left and not root.right: res.append(root.val+value*10) if not root: return 0 else: res = [] helper(root, 0, res) return sum(res)
給定一棵二叉樹,返回前序遍歷
遞歸的方法很是簡單,這裏用棧的方法,建立兩個list,pre用於保存最後的結果,stack用於保存過程當中的結點.若是棧裏還有結點,首先將這個結點出棧,存入pre,而後將這個結點的右結點和左結點存入棧中.
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def preorderTraversal(self, root): """ :type root: TreeNode :rtype: List[int] """ pre = [] stack = [root] while stack: node = stack.pop() if node: pre.append(node.val) stack.append(node.right) stack.append(node.left) return pre
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def preorderTraversal(self, root): """ :type root: TreeNode :rtype: List[int] """ def helper(root, prelist): if root: prelist.append(root.val) helper(root.left, prelist) helper(root.right, prelist) prelist = [] helper(root, prelist) return prelist
給定一棵二叉樹,想象你站在這顆二叉樹的右邊,從上到下給出你能在這棵樹上看到的值.
定義一個數組view和一個輔助函數,它的功能是從右到左遍歷這顆樹,而且當遍歷到的結點深度等於當前view的長度時,代表這是該層最右邊的結點,將它加入view數組,而後遍歷這個結點的右子結點和左子結點.
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def rightSideView(self, root): """ :type root: TreeNode :rtype: List[int] """ def helper(root, depth): if root: if depth == len(view): view.append(root.val) helper(root.right, depth+1) helper(root.left, depth+1) view = [] helper(root, 0) return view
給定一棵徹底二叉樹,求結點數
首先定義一個輔助函數get_depth用於求一顆徹底二叉樹的深度,而後開始構造主函數.若是不存在結點則返回0,不然分別求當前結點的左子樹深度和右子樹深度.若是左子樹深度等於右子樹深度,說明左子樹是滿二叉樹,那麼只需用深度求出左子樹的結點數,而後再對右子樹求結點數便可.若是左子樹深度不等於右子樹深度,那麼說明右子樹是滿二叉樹,同理.
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def countNodes(self, root): """ :type root: TreeNode :rtype: int """ def get_depth(root): depth = 0 while root: root = root.left depth += 1 return depth depth = get_depth(root) if not root: return 0 left_depth = get_depth(root.left) right_depth = get_depth(root.right) if left_depth == right_depth: return pow(2, left_depth) + self.countNodes(root.right) else: return pow(2, right_depth) + self.countNodes(root.left)
翻轉二叉樹
很簡單的一道題.
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def invertTree(self, root): """ :type root: TreeNode :rtype: TreeNode """ if root: tmp = root.right root.right = root.left root.left = tmp self.invertTree(root.left) self.invertTree(root.right) return root
給定一棵二叉樹,其中結點的值表明財產,小偷不能偷兩個相連的結點,求小偷能偷到的最大財產價值.
這種要維護狀態的題首先想到遞歸,用一個大小爲2的一維數組res,res[0]表示不包含當前結點的最大值,res[1]表示包含當前結點的最大值.開始遞歸,若是該結點不存在則返回[0,0],不然left_val等於左結點的遞歸調用,right_val等於右結點的遞歸調用,注意這兩個val實際上都是一個和res大小相同的數組.不包含該結點的話,res[0]=max(left_val)+max(right_val),包含該結點的話,res[1]=root.val+left_val[0]+right_val[0].
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def rob(self, root): """ :type root: TreeNode :rtype: int """ def helper(root): if not root: return [0,0] else: left_val = helper(root.left) right_val = helper(root.right) res = [0,0] res[0] = max(left_val) + max(right_val) res[1] = root.val + left_val[0] + right_val[0] return res return max(helper(root))
DNA是由A,C,G,T四種核苷酸構成的,設計一種算法,可以找到一個DNA裏全部重複出現過的長度爲10的核苷酸序列.
使用python的dict構造哈希表,用i遍歷DNA序列s的第一位到倒數第十位,s[i:i+10]就能夠遍歷其中全部長度爲10的序列.若是在dict中存在這個序列且值等於1(表明出現次數),就將它加入到output的list中,且將值加1.不然將該序列加入dict中,且令值等於1.
class Solution: def findRepeatedDnaSequences(self, s): """ :type s: str :rtype: List[str] """ sub = {} output = [] for i in range(len(s)-9): temp = s[i:i+10] if temp in sub: if sub[temp] == 1: sub[temp] += 1 output.append(temp) else: sub[temp] = 1 return output
給定兩個字符串s和t,判斷它們是否是同構的.同構是指,將其中一個字符串中的相同字符用另外一個字符替換,若是這個字符串能夠變爲另外一個字符串,則稱他們是同構的.
這題個人思路是分別遍歷s和t,用兩個dict存儲結果.若是其中已經有了遍歷到的字符,就令值加1,不然添加該字符,而後用dict.values()進行比較便可.可是提交後出現了錯誤.思考之後發現dict內部存放的順序和key放入的順序沒有關係,由於它是採用哈希表的原理.
正確思路是隻用一個dict,鍵爲s的字母,值爲t相同位置的字母,若是s中的字母已經在dict中了,則判斷對應的鍵是否與此時t中的字母相等,若是不相等則false.若是s中的字母不在dict中,判斷此時t中的字母是否在dict中有值相等,若是有則返回false,不然將該鍵值對存入dict.
class Solution: def isIsomorphic(self, s, t): """ :type s: str :type t: str :rtype: bool """ if len(s) != len(t): return False hashmap = {} for i in range(len(s)): if s[i] in hashmap: if hashmap[s[i]] != t[i]: return False else: if t[i] in hashmap.values(): return False else: hashmap[s[i]] = t[i] return True
給定一個非負數組,表明一位科學家的引用因子,求出這位科學家的H-Index.H-index是指他至多有h篇論文分別被引用了至少h次.
計算H-index的方法是將引用因子降序排好,而後找到第一個比引用因子大的序號,將序號-1就是H-index.
class Solution: def hIndex(self, citations): """ :type citations: List[int] :rtype: int """ if citations == []: return 0 citations.sort(reverse=True) for i in range(len(citations)): if i + 1 > citations[i]: return i return len(citations)
一個猜數字的遊戲,給定目標數secret和猜想數guess,猜想數中和目標數大小相同且位置相同的叫bulls,大小相同但位置不一樣的叫cows,要求給出bulls和cows的數量.
首先用map將secret和guess變爲數字list,另外定義兩個長度爲10的list,而後同時遍歷這兩個list,若是數字相同則bulls+1,不然在對應的list的對應位置+1.遍歷結束後比較list每一個位置的較小者,相加就獲得cows的數量.
class Solution: def getHint(self, secret, guess): """ :type secret: str :type guess: str :rtype: str """ nums1 = list(map(int, secret)) nums2 = list(map(int, guess)) bulls = 0 cows = 0 l1 = [0]*10 l2 = [0]*10 for i in range(len(nums1)): if nums1[i] == nums2[i]: bulls += 1 else: l1[nums1[i]] += 1 l2[nums2[i]] += 1 for i in range(10): cows += min(l1[i], l2[i]) return str(bulls)+'A'+str(cows)+'B'
給定一棵二叉樹,將每一個結點的next結點設爲它右邊的相鄰結點,若是不存在這樣的結點則設爲NULL.
首先創建一個tali結點和一個head結點,其中head結點用於保存tail結點最初的位置.而後遍歷當前root,首先將tail.next指向root.left,若是存在則將tail移動至tail.next,而後將tail.next指向root.right,若是存在則將tail移動至tali.next.遍歷完之後將root指向root.next(由於root比tail高一層,因此root層的next結構已經固定了).若是root存在則重複上述過程,不然將tail指向一開始的head結點,將root指向head的next,即將root下移了一層.
# Definition for binary tree with next pointer. # class TreeLinkNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None # self.next = None class Solution: # @param root, a tree link node # @return nothing def connect(self, root): tail = head = TreeLinkNode(0) while root: tail.next = root.left if tail.next: tail = tail.next tail.next = root.right if tail.next: tail = tail.next root = root.next if not root: tail = head root = head.next
給定一個二維網格,其中'1'表明陸地,'0'表明水.島是指一塊被水包圍的豎直方向和水平方向相連的陸地.假設網格的四周都是水,求其中島的數量.
經典的DFS思想,遍歷網格,若是當前位置是1就調用dfs函數.在dfs中首先進行邊界判斷,而後若是當前位置是'1'則改成'#',以後對位置的先後左右位置調用dfs函數.
class Solution: def numIslands(self, grid): """ :type grid: List[List[str]] :rtype: int """ if not grid: return 0 count = 0 for i in range(len(grid)): for j in range(len(grid[0])): if grid[i][j] == '1': self.dfs(grid, i, j) count += 1 return count def dfs(self, grid, i, j): if i<0 or j<0 or i>=len(grid) or j>=len(grid[0]) or grid[i][j] != '1': return grid[i][j] = '#' self.dfs(grid, i+1, j) self.dfs(grid, i-1, j) self.dfs(grid, i, j+1) self.dfs(grid, i, j-1)
給定一棵二叉樹,判斷它是否是一棵二叉查找樹(左子樹的全部結點都比該結點小,右子樹的全部結點都比該結點大,且左右子樹都是二叉查找樹).
在列表中找到兩個數,使得它們的和等於某一給定值,返回這兩個數的位置.時間複雜度:O(n),python中的字典其實就是哈希表的應用,因此咱們經過字典用哈希表來下降查找的時間複雜度
class Solution: def twoSum(self, nums, target): """ :type nums: List[int] :type target: int :rtype: List[int] """ d = {} for i, n in enumerate(nums): m = target - n if m in d: return [d[m], i] else: d[n] = i
將兩個倒序存放在單鏈表裏的數相加,將結果倒序存儲在單鏈表裏返回.思路很是簡單,先將兩個單鏈表中的數字分別提取出來求和,而後將=求得的和存入一個單鏈表,實際上相加這一步也能夠直接在原鏈表中完成,只須要添加判斷條件while(l1 or l2 or carry)便可.
# Definition for singly-linked list. # class ListNode: # def __init__(self, x): # self.val = x # self.next = None class Solution: def addTwoNumbers(self, l1, l2): """ :type l1: ListNode :type l2: ListNode :rtype: ListNode """ node1 = l1 node2 = l2 l3 = ListNode(0) l3.next = ListNode(0)#[0],[0]的特殊狀況 node3 = l3 sum1 = 0 coe = 1 while not node1 is None: sum1 += node1.val * coe coe *= 10 node1 = node1.next sum2 = 0 coe =1 while not node2 is None: sum2 += node2.val * coe coe *= 10 node2 = node2.next sum = sum1 + sum2 while sum > 0: node3.next = ListNode(sum % 10) node3 = node3.next sum //= 10 return l3.next
找到字符串中沒有重複字符的最大子串.一開始沒有想到用字典,而是直接用str來存儲字串,時間複雜度是O(n^2),後來用字典將時間複雜度降到了O(n).注意到僅當字典中出現重複值且該重複值在strat區段裏時才移動start.另外用了Sliding Window的思想,每次將strat移動到重複值的下一位置.
class Solution: def lengthOfLongestSubstring(self, s): """ :type s: str :rtype: int """ start = 0 max_length = 0 substring = {} for i, c in enumerate(s): if c in substring and start <= substring[c]:#只有當重複值是在start後面出現時才移動start start = substring[c] + 1#Slding Window的思想 else: max_length = max(max_length, i - start + 1) substring[c] = i return max_length
最長迴文子串問題,一開始個人思路以下:迴文子串的特色是首尾字母相同,因此我對每個字母都找到位於它後面的相同字母,利用切片判斷這一段是否爲迴文子串(str[i:j]==str[i:j][::-1]).雖然AC了可是時間複雜度很高,主要是由於str.find操做很是耗時.
後來看了Solution發現這是一道能夠用動態規劃解決的問題,思路是若s是迴文字串,令s'=s加上s左右兩側的兩個字母,若是這兩個字母相同則s'也是迴文字串.重寫代碼以下:
class Solution: def longestPalindrome(self, s): """ :type s: str :rtype: str """ max = 0 palindromic = '' if len(s) == 0 else s[0] for i in range(len(s)): length = 1 while i - length >=0 and i + length < len(s) and s[i-length] == s[i+length]: tmp = s[i-length:i+length+1] if len(tmp) > max: max = len(tmp) palindromic = tmp length += 1 length = 1 while i - length + 1 >=0 and i + length < len(s) and s[i-length+1] == s[i+length]: tmp = s[i-length+1:i+length+1] if len(tmp) > max: max = len(tmp) palindromic = tmp length += 1 return palindromic
這道題還有經典的Manacher算法,能夠看這篇文章.Discuss裏的算法實如今這裏.
另外在Discuss裏發現了另外一種作法,思路是一段迴文字符串的後面新增了一個字母,若是新字符串還是迴文字符串的話只有兩種可能:形如bb+b,也就是多了一個字母,或形如a(bb)+a,算上原迴文字符串的前一個字母共多了兩個字母.基於這個思路能夠寫出代碼.由於用到了切片,在題例上運行的速度甚至比Manacher算法還快.
一道將字符串作之字形排列的題目.咱們用n表示行數,將排列後獲得的字符串分爲完整豎列和折線兩部分.每一個完整豎列有n個數,每兩個完整豎列之間的折線有n-2列,每列一個數,所以每兩個完整豎列中同一行的數的間隔是n+n-2=2n-2.同時咱們發現,除了第一行和最後一行以外的第i行都有折線,第i行的第一個折線是第2n-i個數.因而能夠遍歷輸出每一行,斷定條件是這一行咱們要輸出的數字是否超出了字符串的長度.
class Solution: def convert(self, s, numRows): """ :type s: str :type numRows: int :rtype: str """ zigzag = '' if numRows == 1 or numRows == 0 or numRows >= len(s): return s space = 2 * numRows - 2 for i in range(1,numRows+1): n = 0 if i == 1 or i == numRows: while i + n * space <= len(s): zigzag += s[i+n*space-1] n += 1 else: while i + n * space <= len(s): zigzag += s[i+n*space-1] if (2 * numRows - i) + (n * space) <= len(s): zigzag += s[(2*numRows-i)+(n*space)-1] n += 1 return zigzag ZigZag Conversion
將給定的數字倒序輸出.很是簡單的一道題
class Solution(object): def reverse(self, x): """ :type x: int :rtype: int """ tmp = abs(x) sum = 0 while tmp > 0: sum = sum * 10 + tmp % 10 tmp = tmp // 10 sum = sum if x >= 0 else -sum return sum if sum < 2**31 and sum > -2**31 else 0
將給定字符串中符合條件的一串數字字符轉化爲int類型返回.個人思路是設定標誌位start=0和符號位sign,遍歷字符串,當start=0時遇到空格則continue,遇到+則記錄sign=1,遇到-則記錄sign=-1,遇到數字則記錄數字;當strat=1時表明已經找到了第一個數字或符號位,此時遇到除數字以外的字符都break,遇到數字則繼續記錄數字.注意咱們獲得的整數值不能超過INT_MAX和INT_MIN.後來發現其實用str.strip()函數來去除字符串頭尾的空格會更方便.
class Solution(object): def myAtoi(self, str): """ :type str: str :rtype: int """ ans = 0 start = 0 sign = 0 if str.isspace() is True: print(0) for i in str: if start == 0: if i.isspace() is True: continue if i == '+': sign = 1 elif i == '-': sign = -1 elif i.isdigit() is True: sign = 1 ans = ans * 10 + int(i) else: break start = 1 else: if i.isdigit() is True: ans = ans * 10 + int(i) else: break ans = sign * ans if ans >= 2147483647: return 2147483647 elif ans <= -2147483648: return -2147483648 else: return ans
判斷一個數字是不是迴文數.題目要求不能用額外的空間,不然能夠利用python的字符串切片輕鬆解決.個人思路是求出該整數的位數,判斷第一位數和最後一位數是否相同,若是相同則將位數/100,而後將原數字的首尾兩個數刪除,最後若是位數<1說明是迴文數.
class Solution(object): def isPalindrome(self, x): """ :type x: int :rtype: bool """ if x < 0: return False high = 1 while x / high >= 10: high *= 10 while x // high == x % 10: x = x % high // 10 high /= 100 if high < 1: return True return False
將十進制數字轉化爲羅馬數字.比較簡單的一道題.個人思路是判斷當前位數,改變表明1/5/10的字符而後逐位輸出.也能夠直接將每位上的各類字符表示存在列表裏,而後直接取出.
class Solution(object): def intToRoman(self, num): """ :type num: int :rtype: str """ carry = 1 roman = '' while num != 0: n = num % 10 num //= 10 if carry == 1: numeral_1 = 'I' numeral_5 = 'V' numeral_10 = 'X' elif carry == 10: numeral_1 = 'X' numeral_5 = 'L' numeral_10 = 'C' elif carry == 100: numeral_1 = 'C' numeral_5 = 'D' numeral_10 = 'M' else: numeral_1 = 'M' numeral_5 = '' numeral_10 = '' if 1 <= n <= 3: roman = numeral_1 * n + roman elif n == 4: roman = numeral_1 + numeral_5 + roman elif 5 <= n <= 8: roman = numeral_5 + numeral_1 * (n - 5) + roman elif n == 9: roman = numeral_1 + numeral_10 + roman carry *= 10 return roman
將羅馬數字轉化爲十進制數字.很是無聊的一道題.比較簡單的方法是寫很是多的if語句來判斷,或者將羅馬數字與對應的十進制數字存入字典來轉換.下面是我在discuss裏看到的一個方案,巧妙利用了羅馬數字"大數前面的小數用來減,大數後面的小數用來加"這個特色.
class Solution(object): def romanToInt(self, s): """ :type s: str :rtype: int """ roman_map = { "I": 1, "V": 5, "X": 10, "L": 50, "C": 100, "D": 500, "M": 1000, } result = 0 last_num = None for char in s: current_num = roman_map[char] if last_num is None or last_num >= current_num: result += current_num elif last_num < current_num: result += current_num - 2 * last_num last_num = current_num return result
找最長公共前綴字符串.個人思路是找出列表中最短的字符串,而後對最短字符串的每一個字符都在列表中遍歷,直到出現不一樣或者遍歷結束爲止.在discuss裏看到不少方法利用了python中的sort(),min(),max()這些內置方法對字符串排序,會使時間快不少.
class Solution(object): def longestCommonPrefix(self, strs): """ :type strs: List[str] :rtype: str """ prefix = '' if strs == []: return prefix minimum = float("inf") for s in strs: minimum = min(len(s), minimum) i = 0 for j in range(minimum): for i in range(len(strs)): while strs[i][j] != strs[0][j]: return prefix prefix = prefix + strs[0][j] return prefix
給定一個數組,找到其中三個數的和爲零的全部可能,以列表形式返回.這道題的基本思路是先將數組排序,從左往右遍歷一次.在遍歷每一個數的過程當中設立兩個指針,若是三個數的和大於零則左移右指針,若是三個數的和小於零則右移左指針,直到兩個指針相遇.注意咱們用的是set()來存儲找到的結果,能夠避免list中出現重複.在此基礎上,我增長了一個對排序過的數組的操做,即當最左邊兩個數與最右邊一個數的和大於零時刪去最右邊的數,當最左邊一個數與最右邊兩個數的和小於零時刪去最左邊的數.這個操做大大提高了運行速度.
class Solution(object): def threeSum(self, nums): """ :type nums: List[int] :rtype: List[List[int]] """ zeros = set() nums.sort() if len(nums) < 3: return [] if nums.count(0) > len(nums)-2: return [[0, 0, 0]] while len(nums) > 3 and (nums[0]+nums[1]+nums[-1] > 0 or nums[-1]+nums[-2]+nums[0] < 0): if nums[0] + nums[1] + nums[-1] > 0: nums.remove(nums[-1]) else: nums.remove(nums[0]) for i in range(len(nums)-2): if nums[i] > 0: break j = i + 1 k = len(nums) - 1 while j < k: sum = nums[i] + nums[j] + nums[k] if sum == 0: zeros.add((nums[i], nums[j], nums[k])) j += 1 continue elif sum < 0: j += 1 else: k -= 1 return list(map(list,zeros))