2020 07/13
p1. 给定两个数组,编写一个函数来计算它们的交集。.示例 1: 输入:nums1 = [1,2,2,1], nums2 = [2,2] 输出:[2,2] 示例 2: 输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4] 输出:[4,9]
- 本人采用了最暴力但也是最好想的懒人方法:
遍历短列表,如果长列表中存在就删除,然后将相同的添加到公共列表。方法比较耗时,属于偷懒行为,所以看了别人的方法。
本人方法:
class Solution:
def intersect(self, nums1: List[int], nums2: List[int]) -> List[int]:
same = []
maxList = nums1 if len(nums1) >= len(nums2) else nums2
minList = nums1 if len(nums1) < len(nums2) else nums2
for i in minList:
for j in maxList:
if j == i:
maxList.remove(j)
same.append(i)
break
return same
比较好的方法思路是首先遍历两个列表,统计相同元素成为字典格式,返回两个字典相同键的小值。(只是较好吧,最好利用哈希,但是感觉代码量多了些)
P2. 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。 你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。 示例: 给定 nums = [2, 7, 11, 15],
target = 9 因为 nums[0] + nums[1] = 2 + 7 = 9 所以返回 [0, 1]
我的思路:采用首尾指针遍历,需要首先进行字典化,字典存储键加位置,就算有重复的,如果重复的超过了两个那它一定不是其中一个,因为就不是单一结果了。
处理重复的就是键加上“Q”,然后对数组排序,首尾遍历,如果出现重复值相加为目标值,则肯定是目标值一半。做个判断就好了,然后去字典里取值即可。
```python
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
dict_local = {}
for i, val in enumerate(nums):
if str(val) in dict_local.keys():
dict_local[str(val) + "Q"] = i
else:
print("111")
dict_local[str(val)] = i
print(dict_local)
end = len(nums) - 1
start = 0
result = []
nums.sort()
while start < end and nums:
if nums[start] + nums[end] == target and nums[start] != 0.5 * target:
result.append(dict_local[str(nums[start])])
result.append(dict_local[str(nums[end])])
break
if nums[start] + nums[end] == target and nums[start] == 0.5 * target:
result.append(dict_local[str(nums[start])])
result.append(dict_local[str(nums[end]) + "Q"])
break
if nums[start] + nums[end] > target:
end = end - 1
if nums[start] + nums[end] < target:
start = start + 1
return result
效率还行,占用空间较多。
2020 07/14
给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。 相邻的结点 在这里指的是 下标 与 上一层结点下标
相同或者等于 上一层结点下标 + 1 的两个结点。 例如,给定三角形:[
[2],
[3,4], [6,5,7], [4,1,8,3] ] 自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)。
class Solution:
def minimumTotal(self, triangle: List[List[int]]) -> int:
# 状态转移函数dp[j]=min(dp[j],dp[j+1]) + tri[i][j]
start = triangle[len(triangle) -1] # 初始dp为最下面那一行
for list_ in reversed(triangle[0:-1]):
length = len(list_)
for i in range(length):
start[i] = min(start[i], start[i+1]) + list_[i]
return start[0]
- 动态规划题目一般从最后一个开始,自下向上考虑,核心是找到状态转移方程
本题在从下向上便利的时候,每次肯定需要携带最短路径的信息,这里不考虑路径,只需要路径长度,所以只需要记录每个最短的路径的长度信息,携带上去,每次遍历上一层的列表时,对下面那层每次取相邻两个最小值与当前遍历值相加,重新给初始列表的位置赋值即可。每层赋值都会少改变初始列表的值,顶层只会改变初始列表的第一个元素值,且最小的就是当前这个。
ps:昨夜想的方法是对每一个列表首先初始化成为字典,键为列表元素值,值为该元素在列表中的位置,对于相同的元素,键加个区别符,最后将这些字典添加到一个列表中,再将之前的列表的每一个列表进行排序。最后遍历排序后的列表的时候,每次取第一个,判断第一个元素是不是上一个元素的相邻的,如果不是,就取下一个。。。然后发现逻辑出错。记录一下错误思想。
培养动态规划题目的敏感度。
2020 7/15
给定一个整数 n,求以 1 … n 为节点组成的二叉搜索树有多少种?
示例:
输入: 3 输出: 5 解释: 给定 n = 3, 一共有 5 种不同结构的二叉搜索树:
1 3 3 2 1
\ / / / \
3 2 1 1 3 2
/ / \ \ 2 1 2 3
这里需要知道一个常识:
假设n个节点组成的二叉搜索树有G(n)种,令f(i)为以i为根的二叉搜索树的个数,则G(n) = f(1) + f(2) +…+f(n)
假设以i为根节点,其左子树结点个数为(i-1)个,右子树结点个数为(n-i)个,则有f(i)=G(i-1)G(n-i)
所以:G(n)=G(0)∗G(n−1)+G(1)∗(n−2)+…+G(n−1)∗G(0)
class Solution:
def numTrees(self, n: int) -> int:
f = [0] * (n+1)
f[0] = 1
f[1] = 1
for i in range(2, n+1):
for j in range(1, i+1):
f[i] += f[j-1] * f[i-j]
return f[n]
2020 7/16
给定一个无向图graph,当这个图为二分图时返回true。
如果我们能将一个图的节点集合分割成两个独立的子集A和B,并使图中的每一条边的两个节点一个来自A集合,一个来自B集合,我们就将这个图称为二分图。
graph将会以邻接表方式给出,graph[i]表示图中与节点i相连的所有节点。每个节点都是一个在0到graph.length-1之间的整数。这图中没有自环和平行边:
graph[i] 中不存在i,并且graph[i]中没有重复的值。 示例 1: 输入: [[1,3], [0,2], [1,3],
[0,2]] 输出: true 解释: 无向图如下: 0----1 | | | | 3----2 我们可以将节点分成两组:
{0, 2} 和 {1, 3}。 示例 2: 输入: [[1,2,3], [0,2], [0,1,3], [0,2]] 输出: false
解释: 无向图如下: 0----1 | \ | | \ | 3----2 我们不能将节点分割成两个独立的子集。 注意: graph
的长度范围为 [1, 100]。 graph[i] 中的元素的范围为 [0, graph.length - 1]。 graph[i]
不会包含 i 或者有重复的值。 图是无向的: 如果j 在 graph[i]里边, 那么 i 也会在 graph[j]里边。
- 这道题,冥思苦想了很久,想用递归去处理,于是就踏上了不归路,想了各种特别情况,最后还是不通过,忍不了了,看答案去了,耗了得有4个小时。
想用的递归方法(未通过)
class Solution:
def isBipartite(self, graph) -> bool:
# 无向图G为二分图的充分必要条件是,G至少有两个顶点,且其所有回路的长度均为偶数。
if len(graph) < 2:
return False
else:
length = len(graph)
# 开始判断每个回路长度是否是偶数
for i in range(length):
print(111)
count = 0 # 回路长度
start_list = graph[i]
passed = []
flag = self.IterationFunction(i, start_list, count, graph, passed)
if not flag: # 但凡一个不满足偶数条件直接返回false
return False
else:
pass
return True
def IterationFunction(self, i, list1, count, graph, passed):
Flag = True
for j in list1:
if j in passed:
continue
else:
count = count + 1
if i in graph[j]:
if count == 1:
graph[j].remove(i)
if graph[j]:
passed.append(j)
count = count + 1
return self.IterationFunction(i, graph[j], count, graph, passed)
else:
list1.remove(j)
count -= 1
if list1:
return self.IterationFunction(i, list1, count, graph, passed)
else:
Flag = True
break
elif count % 2 == 0:
# if not list1: # 传过来的起始空了
# Flag = True
# break
# else:
continue
elif count % 2 == 1: # 有不满足的了
Flag = False
break
elif i not in graph[j]:
passed.append(j)
return self.IterationFunction(i, graph[j], count, graph, passed)
return Flag
x = Solution()
print(x.isBipartite([[],[2],[1],[],[],[7,8],[7,8,9],[5,6],[5,6],[6],[12,13,14],[12],[10,11],[10],[10],[18],[17,18],[16],[15,16],[],[22,23,24],[22,23,24],[20,21],[20,21],[20,21],[27,28,29],[27,28,29],[25,26],[25,26],[25,26],[32,33,34],[33],[30],[30,31],[30],[37,39],[38],[35],[36],[35],[44],[43,44],[],[41],[40,41],[47,48,49],[47,48,49],[45,46],[45,46],[45,46]]))
答案:
从一个节点开始,先进行染色标记,对图进行遍历,当前节点的相连的所有节点都标记为与当前节点不同的颜色,表示这里两个相连的节点属于不同的集合,循环遍历。
- 当所有节点都成功染色时,那么颜色会区分开,也就是不同颜色属于不同集合,那么返回 True,说明是二分图。
- 如果没有成功染色,也就是遍历的过程中,会出现节点已经被染色,并且节点颜色与此时要染色的颜色不同,说明出现冲突,直接返回
False,说明不是二分图。
# 深度优先搜索
class Solution:
def isBipartite(self, graph: List[List[int]]) -> bool:
def dfs(graph, node, color, signed):
# 先判断,该节点是否被标记染色,如果被染色,判断这个节点颜色与当前要标记的颜色是否相同
if signed[node] != 0:
return signed[node] == color
# 对当前节点染色,然后对相邻的节点标记不同的颜色
signed[node] = color
for x in graph[node]:
if not dfs(graph, x, -color, signed):
return False
return True
length = len(graph)
# 在这里,0:表示未标记,1、 -1:表示不同的两个颜色
signed = [0] * length
# 这里需要注意,有可能会存在顶点未被访问的情况,
# 那么以这个顶点进行再一次访问
for i in range(length):
if (signed[i] == 0 and not dfs(graph, i, 1, signed)):
return False
return True
# 广度优先搜索
class Solution:
def isBipartite(self, graph: List[List[int]]) -> bool:
from collections import deque
# 创建队列
queue = deque()
length = len(graph)
# 在这里,0:表示未标记,1、 -1:表示不同的两个颜色
# 标记是否被染色
signed = [0] * length
# 可能出现节点未被标记,存在则从它开始进行下一轮的 bfs
for i in range(length):
if signed[i] != 0:
continue
queue.append(i)
signed[i] = 1
# 当一个节点出队后,要将相邻的节点进行标记不同颜色并入队
while queue:
node = queue.popleft()
for x in graph[node]:
# 如果当前节点的相邻节点已经被染色,且两者颜色相同,返回 False,表示无法成功染色
if signed[x] == signed[node]:
return False
# 如果未标记,进行染色,与当前节点颜色不同,并入队
if signed[x] == 0:
signed[x] = -signed[node]
queue.append(x)
return True
2020 07/17
p1.
从上到下打印出二叉树的每个节点,同一层的节点按照从左到右的顺序打印。 例如: 给定二叉树: [3,9,20,null,null,15,7],
3
/
9 20
/
15 7
返回:
[3,9,20,15,7]
.
思路:考察二叉树的广度遍历,给定节点类,从根节点添加到循环列表中,如果左存在,则将左节点的值添加到结果列表,同时将左节点添加到循环列表中等待下次遍历,如右边一样。
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def levelOrder(self, root: TreeNode) -> List[int]:
if root == None:
return []
else:
result = []
temp = []
temp.append(root)
result.append(root.val)
while temp:
current = temp.pop(0)
if current.left:
temp.append(current.left)
result.append(current.left.val)
if current.right:
temp.append(current.right)
result.append(current.right.val)
return result
如果是深度遍历需要分前中后,遇到再说吧,递归可解决。
p2
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
你可以假设数组中无重复元素。
示例 1:
输入: [1,3,5,6], 5 输出: 2
比较简单。。。
class Solution:
def searchInsert(self, nums: List[int], target: int) -> int:
if target in nums:
return nums.index(target)
else:
if target<nums[0]:
return 0
elif target>nums[len(nums)-1]:
return len(nums)
else:
for i in range(len(nums)):
if nums[i] < target and nums[i+1] > target:
return i+1
2020 07/20
p1. 给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数。 函数应该返回这两个下标值 index1 和
index2,其中 index1 必须小于 index2。 说明: 返回的下标值(index1 和 index2)不是从零开始的。
你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。 示例: 输入: numbers = [2, 7, 11, 15],
target = 9 输出: [1,2] 解释: 2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。
比较简单,直接首位指针遍历即可,不解释。
只遍历一趟列表,时间复杂度O(n)
class Solution:
def twoSum(self, numbers: List[int], target: int) -> List[int]:
start = 0
end = len(numbers) - 1
while start < end:
if numbers[start] + numbers[end] < target:
start += 1
if numbers[start] + numbers[end] > target:
end -= 1
if numbers[start] + numbers[end] == target:
return [start+1,end+1]
p2.给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。
如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。 您可以假设除了数字 0 之外,这两个数都不会以 0 开头。 示例:
输入:(2 -> 4 -> 3) + (5 -> 6 -> 4) 输出:7 -> 0 -> 8 原因:342 + 465 = 807
分析可知,题目有两个需要注意的地方,两个链表长度不一样怎么办?每一位发生溢出怎么办?
考虑好这两个问题,问题就迎刃而解。可以设立一个第三个链表,并记录该链表的头(save)
其他两个链表按位相加,溢出则保留1给下一位计算,头链表不存内容,本次相加的和考虑溢出后留给第三个链表初始化next使用。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
save = result = ListNode(None)
rest = 0 # 进一位?
while l1 or l2 or rest:
rest += (l1.val if l1 else 0) + (l2.val if l2 else 0)
result.next = ListNode(rest % 10)
rest = rest // 10
result = result.next
l1 = l1.next if l1 else None
l2 = l2.next if l2 else None
return save.next
2020 07/23
p1. 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如,数组
[3,4,5,1,2] 为 [1,2,3,4,5] 的一个旋转,该数组的最小值为1。 示例 1: 输入:[3,4,5,1,2] 输出:1
示例 2: 输入:[2,2,2,0,1] 输出:0
题目不难,但是像采用首尾遍历的,需要多考虑一些极端情况,比如,元素只有一个,元素相等等很多情况,遇到就记下来吧。
class Solution:
def minArray(self, numbers: List[int]) -> int:
s = 0
e = len(numbers) - 1
# 采用首位指针切记考虑几种特殊情况,数组长度为1 是切记,还有就是所有元素相等情况
if len(numbers) == 1:
return numbers[0]
while numbers[s]>=numbers[e] and s<e:
s += 1
return numbers[s]
p2. 给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。 示例 1: 输入: “abcabcbb” 输出: 3 解释:
因为无重复字符的最长子串是 “abc”,所以其长度为 3。 示例 2: 输入: “bbbbb” 输出: 1 解释:
因为无重复字符的最长子串是 “b”,所以其长度为 1。 示例 3: 输入: “pwwkew” 输出: 3 解释: 因为无重复字符的最长子串是
“wke”,所以其长度为 3。
请注意,你的答案必须是 子串 的长度,“pwke” 是一个子序列,不是子串。
最好想的应该就是诸葛遍历,然后再去遍历剩下的最后取长度做对比了,效率肯定很低。
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
# 最好想的就是暴力求解,直接遍历,虽然时间复杂度肯定会非常高。。
length_max = 0
for i in range(len(s)):
count = 0
list_sub = []
list_sub.append(s[i])
for j in s[i+1:]:
if j not in list_sub:
list_sub.append(j)
count += 1
else:
if len(list_sub)>length_max:
length_max = len(list_sub)
break
if len(list_sub)>length_max:
length_max = len(list_sub)
return length_max
我当然不可能只用这个方法去做,改进版本,每次记录相同元素的位置,下次遍历直接从这个位置的下一个开始遍历就好了,两个相同的元素之间不需要遍历。
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
# 最好想的就是暴力求解,直接遍历,虽然时间复杂度肯定会非常高。。
if len(s) == 1:
return 1
if len(s) > 1:
length_max = 0
i = 0
while i <len(s)-1:
list_sub = []
list_sub.append(s[i])
for j in range(i+1,len(s)):
if s[j] not in list_sub:
list_sub.append(s[j])
else:
index = list_sub.index(s[j])
i += index + 1 # 下一次循环的起点,因为两个相等的量的中间的部分不需要在遍历了
if len(list_sub) > length_max:
length_max = len(list_sub)
break
if j == len(s) - 1:
if len(list_sub) > length_max:
length_max = len(list_sub)
break
return length_max
else:
return 0
我怀疑数据量太少了,按照道理上来说,效率会提升一些,然而并没有。
瞄了一眼答案看到滑动窗口四个字,立马想到,回去修改了下代码:效率击败百分之80多
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
if len(s) > 1:
win = [] # 滑动窗口、
count_max = 0
for i in s:
if i not in win:
win.append(i)
else:
index = win.index(i)
if len(win) > count_max:
count_max = len(win)
win = win[index+1:] if len(win) != 1 else []
win.append(i)
if count_max<len(win):
count_max = len(win)
return count_max
elif len(s)<=1:
return len(s)
2020 07/24
p1. 给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
说明:每次只能向下或者向右移动一步。 示例: 输入: [ [1,3,1], [1,5,1], [4,2,1] ] 输出: 7
解释: 因为路径 1→3→1→1→1 的总和最小。
见识了记忆搜索法:每次走位的时候记录走到这个位置的最短路径,也就反馈在修改这个位置对应的值上。
class Solution:
def minPathSum(self, grid: List[List[int]]) -> int:
# 可采用记忆搜索法,及每个位置都记录了到这个位置的最短路径
for i in range(len(grid)): # 遍历所有行
for j in range(len(grid[0])): #遍历所有列
if i == j ==0: # 左上角元素
continue
elif i == 0: # 当横向走位
grid[i][j] = grid[i][j-1] + grid[i][j]
elif j == 0: # 纵向走位
grid[i][j] = grid[i-1][j] + grid[i][j]
else:
grid[i][j] = min(grid[i-1][j],grid[i][j-1]) + grid[i][j]
return grid[-1][-1]
p2. 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例: 输入:1->2->4,
1->3->4 输出:1->1->2->3->4->4
有序列表的拼接,主要考虑长度不一致,一方遍历可能会先结束如何处理,还有就是设定头节点和保存头结点。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
# 链表题 注意点就是创建表头,并且要记录下表头,因为你最后可能需要返回
head = ListNode(None)
cur = head
while l1 and l2:
if l1.val < l2.val:
cur.next = l1
l1 = l1.next
else:
cur.next = l2
l2 = l2.next
cur = cur.next
if l1: #遍历某一条链表结束了,剩下的直接品过去
cur.next = l1
else:
cur.next=l2
return head.next
2020 7/28
给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。 示例 1: 输入: “babad” 输出:
“bab” 注意: “aba” 也是一个有效答案。 示例 2: 输入: “cbbd” 输出: “bb”
解题思想:我这里采用找中心轴的方法,每次以当前遍历的值为中心点,散开往两头找,去做比较。主要是需要考虑较多特殊情况:
1、出现奇数个相同的值
2、出现偶数个相同值
3、只有一个字符的时候
4、初始值最长回文不能用len()求长度
5、往两头找找到尽头了
总结:题目不难 情况要考虑全面。
class Solution:
def longestPalindrome(self, s: str) -> str:
# 如果只有一个字符
if len(s) == 1:
return s
max_str = ""
for i in range(0,len(s)-1):
# 如果遇到连续俩是一样的 这里还要再分可能出现奇数个相同的,两种遍历比较大小吧
if s[i] == s[i+1]:
max_str = self.find(i,i+1,s,"",max_str) if len(self.find(i,i+1,s,"",max_str)) > len(self.find(i-1,i+1,s,s[i],max_str)) else self.find(i-1,i+1,s,s[i], max_str)
# 如果连续俩不一样,那每个都可以作为中心轴
else:
max_str = self.find(i - 1,i + 1,s,s[i],max_str)
return max_str
def find(self, head, tail, s, str1, max_str):
while head>=0 and tail <=len(s) - 1:
if s[head] == s[tail]:
str1 = s[head] + str1 + s[tail]
head -= 1
tail += 1
else:
break
if max_str:
if len(max_str) < len(str1):
max_str = str1
return max_str
else:
max_str = str1
return max_str
2020 7/29
给定一个正整数 n,将其拆分为至少两个正整数的和,并使这些整数的乘积最大化。 返回你可以获得的最大乘积。 示例 1: 输入: 2 输出: 1
解释: 2 = 1 + 1, 1 × 1 = 1。 示例 2: 输入: 10 输出: 36 解释: 10 = 3 + 3 + 4, 3 ×
3 × 4 = 36。 说明: 你可以假设 n 不小于 2 且不大于 58。
它的数学证明很有趣,可以看下,显示均值不等式证明给定数量的划分时,均分值最大,然后再用求导证明尽量取3时最大。
class Solution:
def integerBreak(self, n: int) -> int:
# 尽可能用3去分,考虑余数012三种
if n <= 3:
return n-1
else:
rest = n % 3 # 余数
count = n // 3
if rest == 0:
return pow(3,count)
if rest == 1:
return pow(3,count-1) * 4
if rest == 2:
return pow(3,count) * 2
2020 7/30
将一个给定字符串根据给定的行数,以从上往下、从左到右进行 Z 字形排列。 比如输入字符串为 “LEETCODEISHIRING” 行数为 3
时,排列如下: L C I R E T O E S I I G E D H N
之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:“LCIRETOESIIGEDHN”。请你实现这个将字符串进行指定行数变换的函数: string convert(string s, int numRows); 示例 1:
输入: s = “LEETCODEISHIRING”, numRows = 3 输出: “LCIRETOESIIGEDHN” 示例 2:
输入: s = “LEETCODEISHIRING”, numRows = 4 输出: “LDREOEIIECIHNTSG” 解释: L
D R E O E I I E C I H N T S G
找规律题。 一定要记住考虑 字符串相关问题 的字符串长度 或者什么参数为0,1 的情况。
class Solution(object):
def convert(self, s, numRows):
if numRows == 1:
return s
result = ""
# 遍历每一行取数据
length = len(s)-1
for i in range(0,numRows):
j = i # 每行第一个元素
if i<=length:
if i !=0 and i !=numRows-1:
result = result + s[j]
j = j + 2*(numRows-i-1)
while j <= length:
result = result + s[j]
j = j + 2*i
if j<=length:
result = result + s[j]
j = j + 2*(numRows-i-1)
elif i == 0 or i == numRows-1:
while j <= length:
result = result + s[j]
j = j + 2*(numRows-1)
return result
2020 08/03
p1.
给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。 示例 1: 输入: 123 输出: 321 示例 2: 输入:
-123 输出: -321 示例 3: 输入: 120 输出: 21 注意: 假设我们的环境只能存储得下 32 位的有符号整数,则其数值范围为 [−231, 231 − 1]。请根据这个假设,如果反转后整数溢出那么就返回 0。
比较简单,思想就是转为字符再转回来。
class Solution(object):
def reverse(self, x):
"""
:type x: int
:rtype: int
"""
if x == 0:
return 0
if x > 0:
str1 = self.reverse1(x)
return 0 if str1 > pow(2,31)-1 else str1
if x < 0:
str1 = str(x)[1:]
str1 = self.reverse1(str1)
return 0 if str1 > pow(2,31) else 0-str1
def reverse1(self,x):
str1 = str(x)
i = len(str1) - 1
while str1[i] == '0':
i -= 1
str1 = str1[:i+1]
str1 = str1[::-1]
str1 = int(str1)
return str1
p2.
请你来实现一个 atoi 函数,使其能将字符串转换成整数。
首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止。接下来的转化规则如下:
如果第一个非空字符为正或者负号时,则将该符号与之后面尽可能多的连续数字字符组合起来,形成一个有符号整数。
假如第一个非空字符是数字,则直接将其与之后连续的数字字符组合起来,形成一个整数。
该字符串在有效的整数部分之后也可能会存在多余的字符,那么这些字符可以被忽略,它们对函数不应该造成影响。
注意:假如该字符串中的第一个非空格字符不是一个有效整数字符、字符串为空或字符串仅包含空白字符时,则你的函数不需要进行转换,即无法进行有效转换。
在任何情况下,若函数不能进行有效的转换时,请返回 0 。 提示: 本题中的空白字符只包括空格字符 ’ ’ 。 假设我们的环境只能存储 32
位大小的有符号整数,那么其数值范围为 [−231, 231 − 1]。如果数值超过这个范围,请返回 INT_MAX (231 − 1)
或 INT_MIN (−231) 。 示例 1: 输入: “42” 输出: 42 示例 2: 输入: " -42" 输出: -42
解释: 第一个非空白字符为 ‘-’, 它是一个负号。
我们尽可能将负号与后面所有连续出现的数字组合起来,最后得到 -42 。 示例 3: 输入: “4193 with words” 输出: 4193 解释: 转换截止于数字 ‘3’ ,因为它的下一个字符不为数字。 示例 4: 输入: “words and 987” 输出:
0 解释: 第一个非空字符是 ‘w’, 但它不是数字或正、负号。
因此无法执行有效的转换。 示例 5: 输入: “-91283472332” 输出: -2147483648 解释: 数字 “-91283472332” 超过 32 位有符号整数范围。
因此返回 INT_MIN (−231) 。
感觉不想动脑子,干脆把几种情况都写出来好了,其实就是一行正则的事情。
class Solution(object):
def myAtoi(self, str):
"""
:type str: str
:rtype: int
"""
data = ["0","1","2","3","4","5","6","7","8","9"]
# 去掉开头结尾的空格
str = str.strip()
# 如果去除空格后字符串的长度仍然不为0
if len(str) >= 2:
i = 0
# 开头是个负号
if str[0] == "-":
i += 1
while i < len(str):
# 说明是数字0-9
if str[i] in data:
i += 1
else:
break
if i == 1: # 说明只有个负号是有效字符,直接返回0
return 0
else:
str = str[1:i]
str = int(str)
if str > pow(2,31):
return 0-pow(2,31)
else:
return 0-str
# +号开头
elif str[0] == '+':
str = str[1:]
while i < len(str):
if str[i] in data:
i += 1
else:
break
if i == 0:
return 0
else:
str = int(str[0:i])
if str > pow(2,31) - 1:
return pow(2,31) -1
else:
return str
# 开头是数字
elif str[0] in data:
while i < len(str):
if str[i] in data:
i += 1
else:
break
str = str[0:i]
str = int(str)
if str > pow(2,31) - 1:
return pow(2,31) -1
else:
return str
# 压根开头就不是数字
elif str[0] not in data:
return 0
# 说明去出空格后只有0或者l个字符
else:
if len(str) == 1:
if str[0] in data:
return int(str[0])
else:
return 0
else:
return 0
2020 08/04
判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。
示例 1:
输入: 121 输出: true 示例 2:
输入: -121 输出: false 解释: 从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。 示例
3:输入: 10 输出: false 解释: 从右向左读, 为 01 。因此它不是一个回文数。 进阶: 你能不将整数转为字符串来解决这个问题吗?
一开始没注意到不要转为字符串解决。先贴上字符串解决的方法。
class Solution(object):
def isPalindrome(self, x):
"""
:type x: int
:rtype: bool
"""
if x < 0:
return False
elif x == 0:
return True
elif x > 0:
str1 = str(x)
str2 = str1[::-1]
if str1 == str2:
return True
else:
return False
如果不用字符串解决来判断的话,需要先思考集中可能性,负数和个位为零的肯定不是,所以直接return False,对于剩下的数,可以考虑折半比较法,如果是偶数个数,则如果是回文数一定会出现,每次不停的%10后的数相加再乘以10叠加的过程会出现和剩下的x相等的情况,奇数位数的则会出现,x和每次不停%10后的数相加后再乘以10的数除以10后的值相等。
class Solution:
def isPalindrome(self, x: int) -> bool:
if x < 0 or (x % 10 == 0 and x != 0):
return False
revertedNumber = 0
while x > revertedNumber:
revertedNumber = revertedNumber * 10 + x % 10
x //= 10
return x == revertedNumber or x == revertedNumber // 10