文章目录
题号69: 二分:实现 int sqrt(int x) 函数
实现 int sqrt(int x) 函数。
计算并返回 x 的平方根,其中 x 是非负整数。
由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。
示例 1: 输入: 4 输出: 2
示例 2: 输入: 8 输出: 2
说明: 8 的平方根是 2.82842…, 由于返回类型是整数,小数部分将被舍去。
该题可以利用牛顿迭代法进行求解:
链接:https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division
python代码:
class Solution(object):
def mySqrt(self, x):
"""
:type x: int
:rtype: int
"""
if x <= 1:
return x
else:
xk = x
while x / xk < xk:
xk = (xk + x / xk) // 2
return int(xk)
题目160:链表:链表相交
题目描述:编写一个程序,找到两个单链表相交的起始节点。
如下面的两个链表:
第一种方法:先计算两个链表的长度差,然后分别向后遍历,找到第一个引用相同的节点
代码:
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def getIntersectionNode(self, headA, headB):
"""
:type head1, head1: ListNode
:rtype: ListNode
"""
currentA = headA
currentB = headB
skipA = 0
skipB = 0
while currentA:
currentA = currentA.next
skipA += 1
while currentB:
currentB = currentB.next
skipB += 1
if skipA >= skipB:
gap = skipA - skipB
while gap:
headA = headA.next
gap -= 1
while headA and headB:
if headA == headB:
return headA
headA = headA.next
headB = headB.next
return
else:
gap = skipB - skipA
while gap:
headB = headB.next
gap -= 1
while headA and headB:
if headA == headB:
return headA
headA = headA.next
headB = headB.next
return
第二种方法:
法3: 同时对A和B进行遍历, 并且让到达末尾的指针指向另一个链表的头结点. 例如A: 6->7->4->5; B: 1->2->3->4->5 遍历时会相交于4 (67451234, 12345674).
代码:
def getIntersectionNode(self, headA, headB):
"""
:type head1, head1: ListNode
:rtype: ListNode
"""
p1 = headA
p2 = headB
while p1 != p2:
p1 = p1.next if p1 else headB
p2 = p2.next if p2 else headA
return p1
题号1 哈希表:两数之和
哈希表就是一种以 键-值(key-indexed) 存储数据的结构,我们只要输入待查找的值即key,即可查找到其对应的值。
哈希的思路很简单,如果所有的键都是整数,那么就可以使用一个简单的无序数组来实现:将键作为索引,值即为其对应的值,这样就可以快速访问任意键的值。这是对于简单的键的情况,我们将其扩展到可以处理更加复杂的类型的键。
题目描述:
给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。
例:
给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]
思路:先定义一个空字典,对数组进行遍历,判断每一个差是否在字典里
代码:
class Solution(object):
def twoSum(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
# n = len(nums)
# for i in range(n):
# diff = target - nums[i]
# if diff in nums[i+1:]:
# return list([i, nums[i+1:].index(diff) + i + 1])
n = len(nums)
d = {}
for i in range(n):
diff = target - nums[i]
if nums[i] in d:
return [d[nums[i]], i]
else:
d[diff] = i
题号242 :字符串:字母异位词
题目描述:
给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的一个字母异位词。
示例:
输入: s = "anagram", t = "nagaram"
输出: true
思路:
- 什么是异位词
两个单词如果包含相同的字母,次序不同,则称为字母易位词(anagram)
- 异位词特点
字符数相同/顺序不同/出现字符相同
- 思路
既然是找寻字符串的不同,那我们可以直接建立对应的 哈希表,来对两个 hash 表 进行操作
在比对的时候可以达到O(1)的复杂度
代码:
class Solution(object):
def isAnagram(self, s, t):
"""
:type s: str
:type t: str
:rtype: bool
"""
# ss = sorted(s)
# tt = sorted(t)
# if ss == tt:
# return True
# else:
# return False
dicts, dictt = {}, {}
for ss in s:
if ss in dicts:
dicts[ss] += 1
else:
dicts[ss] = 1
for tt in t:
if tt in dictt:
dictt[tt] += 1
else:
dictt[tt] = 1
return dicts == dictt
题号26. 删除排序数组中的重复项
给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。
不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。
给定 nums = [0,0,1,1,1,2,2,3,3,4],
函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。
你不需要考虑数组中超出新长度后面的元素。
代码:
class Solution:
def removeDuplicates(self, nums: List[int]) -> int:
if len(nums) == 0:
return 0
i = 0
for j in range(len(nums)-1):
if nums[j] == nums[j+1]:
continue
else:
i += 1
nums[i] = nums[j+1]
return i+1
思路:双指针法
数组完成排序后,我们可以放置两个指针
i
i
i 和
j
j
j,其中
i
i
i 是慢指针,而
j
j
j 是快指针。只要
n
u
m
s
[
i
]
=
n
u
m
s
[
j
]
nums[i] = nums[j]
nums[i]=nums[j],我们就增加
j
j
j 以跳过重复项。
当我们遇到
n
u
m
s
[
j
]
!
=
n
u
m
s
[
i
]
nums[j] != nums[i]
nums[j]!=nums[i] 时,跳过重复项的运行已经结束,因此我们必须把它
n
u
m
s
[
j
]
nums[j]
nums[j]的值复制到
n
u
m
s
[
i
+
1
]
nums[i + 1]
nums[i+1]。然后递增
i
i
i,接着我们将再次重复相同的过程,直到
j
j
j 到达数组的末尾为止。
题号 27. 移除元素
给定一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,返回移除后数组的新长度。
不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
给定 nums = [0,1,2,2,3,0,4,2], val = 2,
函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。
注意这五个元素可为任意顺序。
你不需要考虑数组中超出新长度后面的元素。
思路:双指针法
放置两个指针:慢指针
i
i
i和快指针
j
j
j,只要
n
u
m
s
[
j
]
=
v
a
l
nums[j] = val
nums[j]=val, continue,
j
+
1
j+1
j+1;
否则,
n
u
m
s
[
i
]
=
n
u
m
s
[
j
]
nums[i] = nums[j]
nums[i]=nums[j],并且令
i
=
i
+
1
i=i+1
i=i+1,循环到j遍历所有元素
class Solution:
def removeElement(self, nums: List[int], val: int) -> int:
i = 0
for j in range(len(nums)):
if nums[j] == val:
continue
else:
nums[i] = nums[j]
i += 1
return i
题号 35. 搜索插入位置
https://leetcode-cn.com/problems/search-insert-position/
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
你可以假设数组中无重复元素。
输入: [1,3,5,6], 5
输出: 2
三种思路:
一:二分查找法
class Solution:
def searchInsert(self, nums: List[int], target: int) -> int:
low = 0
high = len(nums)
while low<high:
mid = low + (high - low) // 2
if nums[mid] < target:
low = mid + 1
elif nums[mid] > target:
high = mid
else:
return mid
return low
二:for循环
class Solution:
def searchInsert(self, nums: List[int], target: int) -> int:
for i, num in enumerate(nums):
if num >= target:
return i
return i+1
三:取出所有小于或等于target的元素,组成新列表
class Solution:
def searchInsert(self, nums: List[int], target: int) -> int:
left = [i for i in nums if i <= target]
if left == []:
return 0
if left[-1] == target:
return len(left) - 1
else:
return len(left)
题号 38. 报数
报数序列是一个整数序列,按照其中的整数的顺序进行报数,得到下一个数。其前五项如下:
- 1
- 11
- 21
- 1211
- 111221
1 被读作 “one 1” (“一个一”) , 即 11。
11 被读作 “two 1s” (“两个一”), 即 21。
21 被读作 “one 2”, “one 1” (“一个二” , “一个一”) , 即 1211。
给定一个正整数 n(1 ≤ n ≤ 30),输出报数序列的第 n 项。
注意:整数顺序将表示为一个字符串。
我的思路:
利用for循环遍历上一次的字符串,判断下一个是否与前一个元素相同,如果相同则计数,如果不相同则更新新生成的字符串,重置计数
class Solution:
def countAndSay(self, n: int) -> str:
if n == 1:
return '1'
if n == 2:
return '11'
result = '11'
i = 3
while i <= n:
new = ''
p = result[0]
count = 0
for j in range(len(result)):
if result[j] == p:
count += 1
else:
new = new + str(count) + result[j-1]
count = 1
p = result[j]
new = new + str(count) + result[j]
result = new
i += 1
return result
题号 53. 最大子序和
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6
- 基于动态规划
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
for i in range(1, len(nums)):
nums[i] = nums[i] + max(nums[i-1], 0)
return max(nums)
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
sum = 0
max_sum = nums[0]
for i in range(len(nums)):
sum += nums[i]
if sum > max_sum:
max_sum = sum
if sum < 0:
sum = 0
return max_sum
- 基于分治策略
题号 70. 爬楼梯
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
解析:
code:
class Solution:
def climbStairs(self, n: int) -> int:
d = []
d.append(0)
d.append(1)
d.append(2)
if n >= 3:
for i in range(3, n+1):
d.append(d[i-1] + d[i-2])
return d[n]
数学大法好
上图中B应该取负号
code:
class Solution:
def climbStairs(self, n: int) -> int:
import math
sqrt_5 = math.sqrt(5)
return int((math.pow((1 + sqrt_5)/2, n+1) - math.pow((1 - sqrt_5)/2, n+1))/sqrt_5)
有在GitHub上看到一段非常简洁的代码:
class Solution:
def climbStairs(self, n: int) -> int:
from functools import reduce
return reduce(lambda r, _: (r[1], sum(r)), range(n), (1, 1))[0]
dp递归方程:到达当前楼梯的路径数 = 到达上个楼梯的路径数 + 到达上上个楼梯的路径数
这里用一个元组 r 来储存(当前楼梯路径数,下一层楼梯路径数)
利用 reduce 来代替for循环。