其实字节的面的coding真的不难,因为不一定是题库里面的,所以一些特殊的case其实也没有,主要还是自己输入case进行尝试,所以难度已经其实大大降低了,重点是保证思路正确,bug-free.
注意:
len(" ") = 2, len(“”) = 0
把字符串转换成整数
值得注意的点,不可以直接使用"5" - “4”,字符不可以直接与字符运算,可以使用ord(),转换为ASCII码.
class Solution:
def StrToInt(self, s):
# write code here
if not s:
return 0
out = 0
while s[0] == " ":
s = s[1:]
for i in range(len(s)):
if i == 0 and (s[i] == "+" or s[i] == "-"):
continue
elif s[i] == ".":
break
elif s[i] > "9" or s[i] < "0":
return 0
else:
out = out * 10 + (ord(s[i]) - ord("0"))
if s[0] == "-":
return -out
else:
return out
链表倒数第k个节点
class Solution:
def FindKthToTail(self , pHead , k ):
# write code here
if k <= 0:###漏洞~~如果k<=0,牛客考虑一定要面面俱到
return
if not pHead:
return
num = 1
head1 = pHead
head2 = pHead
while head1.next:
head1 = head1.next
if num >= k:
head2 = head2.next
num += 1
if num < k:
return
return head2
逆序对
其实这道题的关键是想到排序,逆序的话,那么只要纠正序的数量求出来即可.首先想一想快排,快排不行,因为快排会改变了原有的相对顺序,也就是之前说的稳定性比较低–虽然稳定性指的是相同的数,前后的相对位置改变了.
所以想到归并排序,可以直到归并排序是先分后并,所以相对位置是不会改变的.即可通过归并排序的过程发现的逆序对的数量进行叠加即可.
class Solution:
def InversePairs(self, data):
# write code here
# 归并排序
if not data:
return 0
self.count = 0
# def merge(data, left, mid, right):
# nums1 = data[left:mid+1]
# nums2 = data[mid+1:right+1]
# res1 = 0
# res2 = 0
# res = []
# while res1 < len(nums1) and res2 < len(nums2):
# if nums1[res1] <= nums2[res2]:
# res.append(nums1[res1])
# res1 += 1
# else:
# res.append(nums2[res2])
# res2 += 1
# self.count += mid+1-left-res1 # 难点~~~只是加上当前还没归类的部分而已!!
# if res1 == len(nums1):
# res += nums2[res2:]
# else:
# res += nums1[res1:]
# data[left:right+1] = res[:]
def merge(data, left, mid, right):
nums1 = data[left:mid+1]
nums2 = data[mid+1:right+1]
res1 = 0
res2 = 0
for i in range(left, right+1):
if res1 < mid+1-left and res2 < right-mid:
if nums1[res1] <= nums2[res2]:
data[i] = nums1[res1]
res1 += 1
else:
data[i] = nums2[res2]
res2 += 1
self.count += mid+1-left-res1 # 难点~~~只是加上当前还没归类的部分而已!
elif res1 < mid+1-left:
data[i] = nums1[res1]
res1 += 1
else:
data[i] = nums2[res2]
res2 += 1
def merge_sort(data, left, right): # 这里的right应该是可以取到的
if left < right:
mid = (left + right)//2
merge_sort(data, left, mid)
merge_sort(data, mid+1, right)
merge(data, left, mid, right)
merge_sort(data, 0, len(data)-1)
return self.count%1000000007
剪绳子
这题可以使用DP,也可以通过数学推导得到尽量分到2/3
*DP就是dp[n]代表n长度可以得到的最大乘积,转移就是dp[n] = dp[n-i]dp[i]–需要注意的一点是大于4的肯定是拆了更好,但是2/3不拆更好,所以先排除这两种情况.
# -*- coding:utf-8 -*-
class Solution:
def cutRope(self, number):
# write code here
# 其实至少剪两段
if number == 2:
return 1
if number == 3:
return 2
if number <= 1:
return
dp = [0]*(1+number)
for i in range(1, number+1):
if i == 1:
dp[i] = 1
elif i == 2:
dp[i] = 2
elif i == 3:
dp[i] = 3
else:
for j in range(2, i-1): #不会剪成1的.
dp[i] = max(dp[i], dp[i-j]*dp[j])
return dp[-1]
# 这里会有个问题,不一定要拆开,可能不拆更大~其实只有2/3会有顾虑,其他肯定是拆开更大.
数值的整数次方
# -*- coding:utf-8 -*-
# bug_free的关键是先考虑好所有的边界情况,一般来说边界满足了,都可以满足.
class Solution:
def Power(self, base, exponent):
# write code here
if base == 0:
return 0
if exponent == 0:
return 1
if exponent < 0:
reverse = 1
exponent = abs(exponent)
else:
reverse = 0
out = 1 # 注意初始值
if exponent % 2 == 0:
while exponent > 1:
out = base * base
exponent = exponent // 2
base = out
else:
exponent -= 1
res = base
while exponent > 1:
out = base * base
exponent = exponent // 2
base = out
out *= res
if reverse:
return 1/out
return out
打印从1到最大的n位数
虽然python不需要考虑大数问题,但是还是为了面试谨慎.—掌握大数问题,解决办法就是通过字符串来实现,也就是得到n位数的全排列,然后把字符后转化成数.
class Solution:
def printNumbers(self, n: int) -> List[int]:
if n < 1:
return []
out = []
def backtrack(n, num):
if len(num) == n:
for j in range(len(num)):
if num[j] != "0":
out.append(int(num[j:]))
return
return
for i in range(10):
add = str(i)
backtrack(n, num+add)
backtrack(n, "")
return out
正则表达式的匹配
class Solution:
def match(self , str , pattern ):
if not str and not pattern:
return True
elif not pattern:
return False
elif not str and pattern[-1] != "*":
return False
def is_match(str, pattern):
while pattern and pattern[0] == "*":
pattern = pattern[1:]
if not str and not pattern:
return True
elif not pattern:
return False
elif not str:
if pattern[-1] != "*": # 关键直接破除~~
return False
else:
return True
if len(pattern) > 1 and pattern[1] == "*":
# 本次递归,重复一次 或者 重复0次
if pattern[0] in {
str[0], "."}: ### 这次出错地方
return is_match(str[1:], pattern) or is_match(str, pattern[2:])
else:
return is_match(str, pattern[2:])
else:
if pattern[0] in {
str[0], "."}:
return is_match(str[1:], pattern[1:])
else:
return False
return is_match(str, pattern)
表示数值的字符串
技巧,分成e前和e后两个子串进行判断比较简单~~
class Solution:
def isNumeric(self , str ):
# write code here
if not str:
return True
if str == "+" or str == "-" or str=="E" or str == "e":
return False
if str[-1] == "e" or str[-1] == "E":
return False
done_o = 0
res1 = ""
res2 = ""
for i in range(len(str)):
if str[i] == "e" or str[i] == "E":
res1 = str[0:i]
res2 = str[i+1:]
break
if not res1 and not res2:
res1 = str
for i in range(len(res1)):
if res1[i] == "+" or res1[i] == "-":
if i != 0:
return False
if res1[i] not in ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ".", "+", "-"]:
return False
if done_o:
if res1[i] == ".":
return False
if res1[i] == ".":
if i == 0:
return False
done_o = 1
for i in range(len(res2)):
if res2[i] == ".":
return False
if res2[i] == "+" or res2[i] == "-":
if i != 0:
return False
if res2[i] not in ["+", "-", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]:
return False
return True
两道回溯法—解决
套框架还是很轻松的
矩阵中的路径
class Solution:
def hasPath(self , matrix , rows , cols , str ):
# write code here
res = []
for i in range(cols, len(matrix)+1, cols):
res.append(matrix[i-cols:i])
matrix = res
if not str:
return True
if rows <= 0 or cols <= 0:
return False
if rows == 1 and cols == 1:
return matrix[0][0] == str[0]
dp = []
for i in range(rows):
dp.append([0]*cols)
self.rows = rows
self.cols = cols
def backtrack(row, col, str):
if not str:
return True
if col >= self.cols or col < 0 or row >= self.rows or row < 0:
return False
if dp[row][col]:
return False
if matrix[row][col] == str[0]:
if len(str) == 1: ####### 要判断[1:]是否有效~~
return True
dp[row][col] = 1
if backtrack(row+1, col, str[1:]) or backtrack(row, col+1, str[1:]) \
or backtrack(row-1, col, str[1:]) or backtrack(row, col-1, str[1:]):
dp[row][col] = 0
return True
else:
dp[row][col] = 0
return False
else:
return False
for i in range(rows):
for j in range(cols):
if backtrack(i, j, str):
return True
return False
机器人的运动范围
#这题有个注意点:是可以返回的,所以下面设置的self.maximum是每次走过一个格子就加一次.
#也就是每个方向能走最远的路程相加,不是说走一条路,就不能回头的那种~~~
# dp[i][j] = 0 #如果是挑选最长的某一条路,才需要!!!
解法一:
class Solution:
def movingCount(self, threshold, rows, cols):
# write code here
# 回溯
if not rows or not cols:
return 0
self.threshold = threshold
dp = []
self.maximum = 0
for i in range(rows):
dp.append([0] * cols)
def get_sum(num):
out = 0
while num > 0:
out += num % 10
num //= 10
return out
def backtrack(i, j, out):
if i < 0 or i >= rows or j < 0 or j >= cols:
return
if not dp[i][j]:
sum = get_sum(i) + get_sum(j)
if sum > self.threshold:
dp[i][j] = 1
return
else:
# if out + 1 > self.maximum: #应该是求和的关系~~不是求最大,可以返回走过的地方
self.maximum += 1
dp[i][j] = 1 #走过了不用再走
backtrack(i + 1, j, out + 1)
backtrack(i - 1, j, out + 1)
backtrack(i, j + 1, out + 1)
backtrack(i, j - 1, out + 1)
# dp[i][j] = 0 #如果是挑选最长的某一条路,才需要!!!!!!!!!
else:
return
backtrack(0, 0, 0)
return self.maximum
解法二:直接返回每个方向能走多远,并相加
class Solution:
def movingCount(self, threshold, rows, cols):
# write code here
# 回溯
if not rows or not cols:
return 0
self.threshold = threshold
dp = []
for i in range(rows):
dp.append([0] * cols)
def get_sum(num):
out = 0
while num > 0:
out += num % 10
num //= 10
return out
def backtrack(i, j, out):
if i < 0 or i >= rows or j < 0 or j >= cols:
return out
if not dp[i][j]:
sum = get_sum(i) + get_sum(j)
if sum > self.threshold:
dp[i][j] = 1
return out
else:
dp[i][j] = 1
out += backtrack(i + 1, j, 0) + \
backtrack(i - 1, j, 0) + \
backtrack(i, j + 1, 0) + \
backtrack(i, j - 1, 0) + 1
return out
else:
return out
return backtrack(0, 0, 0)
旋转数组的最小元素
三种情况, (mid>right)mid属于左数组,那么最小的数肯定在[mid+1, right];
(mid<right),mid属于右数组,最小的数肯定在[left, mid];
mid==right,则无法确认属于左数组还是右,故right-1—必须保证范围缩小.
错误答案:case:
其实这里应该考虑:[100, 1000, 8, 9, 9, 9, 9, 9, 9]:mid属于左数组—错了!!
#100 100 100 100 100 100 100 9 9 9 9 9 9 100 : mid属于右数组
这两种情况
# -*- coding:utf-8 -*-
class Solution:
def minNumberInRotateArray(self, rotateArray):
# write code here
if not rotateArray:
return 0
def half_search(nums, left, right):
while left <= right:
mid = (left + right)//2
if nums[mid] >= nums[right]:
left = mid + 1 # 这种情况没有考虑可能出现在左数组中:[100, 1000, 8, 9, 9, 9, 9, 9, 9]
else:
right = mid
return right
return rotateArray[half_search(rotateArray, 0, len(rotateArray) - 1)]
正确答案
class Solution:
def minArray(self, rotateArray):
# write code here
if not rotateArray:
return 0
def half_search(nums, left, right):
while left < right:
mid = (left + right)//2
if nums[mid] > nums[right]:
left = mid + 1
elif nums[mid] < nums[right]:
right = mid
else:
right -= 1
return right
return rotateArray[half_search(rotateArray, 0, len(rotateArray) - 1)]
二分搜搜:找最左边,找最右边
最简单就是通过[8, 8]两个相邻元素来判断了.
def binary_search_left(nums, left, right, target):
while left < right:
mid = (left + right) // 2
if nums[mid] < target:
left = mid + 1
elif nums[mid] > target:
right = mid - 1
else:
right = mid
return right
def binary_search_right(nums, left, right, target):
while left < right:
mid = (left + right) // 2
if nums[mid] <= target:
left = mid + 1
elif nums[mid] > target:
right = mid - 1
else:
left = mid + 1
return left
二叉搜索树的后序遍历序列
这题很像已知前序遍历和中序遍历重建二叉树,都是从根节点出发的~~
# -*- coding:utf-8 -*-
class Solution:
def VerifySquenceOfBST(self, sequence):
# write code here
# 本题是从根节点入手的~~
if not sequence:
return False
def is_BST(sequence):
done = 0
res = 0
if len(sequence) == 1:
return True
for i in range(0, len(sequence)-1):
if not done and sequence[i] > sequence[-1]: 一旦比根节点大,那么后续必然都比根节点大.
res = i
done = 1
if done and sequence[i] < sequence[-1]:
return False
if not res: # 全部比根节点小,是对的
return True
return is_BST(sequence[0:res]) and is_BST(sequence[res:len(sequence)-1])
return is_BST(sequence)
复杂链表复制
class Solution:
# 返回 RandomListNode
def Clone(self, pHead):
# write code here
if not pHead:
return
record = {
}
head1 = pHead
num = 0
while head1:
if head1 in record:
head = record[head1]
else:
head = RandomListNode(head1.label)
if num == 0:
first = head
num += 1
record[head1] = head
if not head1.random:
head.random = None
elif head1.random in record:
head.random = record[head1.random]
else:
head.random = RandomListNode(head1.random.label)
record[head1.random] = head.random
if not head1.next:
head.next = None
elif head1.next in record:
head.next = record[head1.next]
else:
head.next = RandomListNode(head1.next.label)
record[head1.next] = head.next
head1 = head1.next
return first
把数组排成最小的数
这道题说难不难,也不简单,刚开始尝试使用回溯法得到所有的组合,然后进行比较得到最小的,这样的时间复杂度太高,并且出现一个错误就是比较的时候转换为了int,这个题目有隐含的大数问题,最好是使用字符串进行比较。
若拼接字符串 x + y > y + xx+y>y+x ,则 xx “大于” yy ;
反之,若 x + y < y + xx+y<y+x ,则 xx “小于” yy ;
如果转换为int会出现说明里出现的情况无法正确对待,int(“0123445”) = 123445,所以不能直接转换为int。
下面是直接结合某一种排序方法进行,结合对应的判断规则即可。
# 若拼接字符串 x + y > y + xx+y>y+x ,则 xx “大于” yy ;
# 反之,若 x + y < y + xx+y<y+x ,则 xx “小于” yy ;
# 使用快排
class Solution:
def minNumber(self, nums: List[int]) -> str:
if not nums:
return ""
def partition(nums, left, right):
res1 = left - 1
res2 = left - 1
key = nums[right]
for i in range(left, right):
if nums[i] + key <= key + nums[i]:
res1 += 1
res2 += 1
nums[res1], nums[res2] = nums[res2], nums[res1]
else:
res2 += 1
#!!!!!!! nums[res1+1], nums[-1] = nums[-1], nums[res1+1]
nums[res1+1], nums[right] = nums[right], nums[res1+1]
return res1+1
def quick_sort(nums, left, right):
if left < right:
res = partition(nums, left, right)
quick_sort(nums, left, res-1)
quick_sort(nums, res+1, right)
for i in range(len(nums)):
nums[i] = str(nums[i])
quick_sort(nums, 0, len(nums) - 1)
return "".join(nums)
把数字翻译成字符串
说到底也就是dp[i] = dp[i-1] + dp[i-2]
class Solution:
def translateNum(self, num: int) -> int:
# 递归解决
record = {
}
char = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", \
"o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
for i in range(26):
record["%s"%i] = char[i]
num = str(num)
self.out = 0
def translate(num, sub):
if not num:
self.out += 1
return
translate(num[1:], sub+record[num[0]])
if len(num) > 1 and num[0:2] in record:
translate(num[2:], sub+record[num[0:2]])
translate(num, "")
return self.out
# 上述递归办法有重叠子问题。12258为例: 12 258, 1 2 258
## 动态规划
# dp[i] = dp[i-1] + dp[i-2]
class Solution:
def translateNum(self, num: int) -> int:
# 递归解决
record = {
}
char = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", \
"o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
for i in range(26):
record["%s"%i] = char[i]
num = str(num)
self.out = 0
dp = [0]*(len(num)+1)
dp[0] = 1
dp[1] = 1
for i in range(2, len(num)+1):
if num[i-2:i] in record:
dp[i] = dp[i-1] + dp[i-2]
else:
dp[i] = dp[i-1]
return dp[-1]
# 初始状态: dp[0] = dp[1] = dp[0] = dp[1] = 1 ,即 “无数字” 和 “第 11 位数字” 的翻译方法数量均为 11 ;
# 返回值: dp[n]dp[n] ,即此数字的翻译方案数量。
# Q: 无数字情况 dp[0] = 1dp[0]=1 从何而来?
# A: 当 numnum 第 1, 21,2 位的组成的数字 \in [10,25]∈[10,25] 时,显然应有 22 种翻译方法,即 dp[2] = dp[1] + dp[0] = 2dp[2]=dp[1]+dp[0]=2 ,而显然 dp[1] = 1dp[1]=1 ,因此推出 dp[0] = 1dp[0]=1 。
礼物的最大价值
class Solution:
def maxValue(self, grid: List[List[int]]) -> int:
if not grid:
return 0
# 动态规划
m = len(grid)
n = len(grid[0])
dp = []
for i in range(m):
dp.append([0]*n)
for i in range(m):
for j in range(n):
if i == 0 and j == 0:
dp[i][j] = grid[i][j]
elif i == 0:
dp[i][j] = dp[i][j-1] + grid[i][j]
elif j == 0:
dp[i][j] = dp[i-1][j] + grid[i][j]
else:
dp[i][j] = max(dp[i-1][j], dp[i][j-1]) + grid[i][j]
return dp[-1][-1]
最长不含重复字符的子字符串
最容易的想是字典的办法,但是问题是老的保存会影响现在的情况。所以关键是能否使用额外的条件判别。不可以自认为替换掉了,到那时除了替换掉的那一个之外,前面的其实没有被替换
class Solution:
def lengthOfLongestSubstring(self , arr ):
# write code here
# 这道题开始出现的问题在于没有意识到,如果是一个新的开始,那么其实前面进入字典的键不再生效,从上一个重复的键之前的那些键,所以这种做法是通过OrderedDict的有序性来解除这种危机。
# length = end - start + 1
########################################################## 致命错误。
# "abba" , 当走到第三个的时候,start变成了b,但是a仍保留在了dict里面~~
########################################################## 致命错误。
# 解决通过引入判断条件,是否大于length来判断~
if not len(arr):
return 0
record = {
}
lengths = []
length = 0
longest = 0
start = 0
for i in range(len(arr)):
if arr[i] not in record:
record[arr[i]] = i
length += 1
else:
#######################################
if i - record[arr[i]] + 1 > length + 1:
record[arr[i]] = i
length += 1
continue
####################################### 有时候需要多开动脑筋想象办法
if length > longest:
longest = length
index = record[arr[i]]
length = i - (index + 1) + 1
start = index + 1
record[arr[i]] = i
if length > longest:
longest = length
return longest