mirror of
https://github.com/SunnyQjm/algorithm-review.git
synced 2026-06-15 14:04:49 +08:00
add: chapter1, chapter2, chapter3
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
#!/usr/bin/env python
|
||||
# coding=utf-8
|
||||
|
||||
###############################################################
|
||||
# Leetcode 70
|
||||
# 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
|
||||
# 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
|
||||
#
|
||||
# 注意:给定 n 是一个正整数。
|
||||
#
|
||||
# 示例 1:
|
||||
# 输入: 2
|
||||
# 输出: 2
|
||||
# 解释: 有两种方法可以爬到楼顶。
|
||||
# 1. 1 阶 + 1 阶
|
||||
# 2. 2 阶
|
||||
#
|
||||
# 示例 2:
|
||||
# 输入: 3
|
||||
# 输出: 3
|
||||
# 解释: 有三种方法可以爬到楼顶。
|
||||
# 1. 1 阶 + 1 阶 + 1 阶
|
||||
# 2. 1 阶 + 2 阶
|
||||
# 3. 2 阶 + 1 阶
|
||||
###############################################################
|
||||
|
||||
class Solution:
|
||||
def climbingStairs(self, n):
|
||||
"""
|
||||
(Knowledge)
|
||||
|
||||
思路:
|
||||
1. 想要到第n个台阶,可以从n-1层爬一个台阶到达,或者从n-2层爬两个台阶到达;
|
||||
|
||||
2. 令f(n)位到达第n个台阶的方法数,则有:f(n) = f(n - 1) + f(n - 2) => 状态转移方程
|
||||
|
||||
3. 由于从下往上计算到达每个台阶的方法数时,只需要前两个台阶的方法数,所以只需要用两个变量保存状态即可
|
||||
"""
|
||||
pre, cur = 0, 1
|
||||
for i in range(n):
|
||||
pre, cur = cur, pre + cur
|
||||
return cur
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
solution = Solution()
|
||||
print(solution.climbingStairs(2))
|
||||
print(solution.climbingStairs(3))
|
||||
print(solution.climbingStairs(4))
|
||||
@@ -0,0 +1,48 @@
|
||||
#!/usr/bin/env python
|
||||
# coding=utf-8
|
||||
|
||||
|
||||
################################################################3
|
||||
# LeetCode: 69 Sqrt(x)
|
||||
# Implement int sqrt(int x).
|
||||
# Compute and return the square root of x, where x is guaranteedto be a non-negative integer.
|
||||
# Since the return type is an integer, the decimal digits aretruncated and only the integer part of the result is returned.
|
||||
################################################################3
|
||||
|
||||
class Solution:
|
||||
def mySqrt(self, x):
|
||||
"""
|
||||
(Knowledge)
|
||||
|
||||
函数功能描述: 传入一个数字,返回其平方根的整数部分
|
||||
|
||||
思路:
|
||||
1. 首先用特判,处理掉x=1的特殊情况;
|
||||
2. 接着用二分法,找到x平方根的整数部分;
|
||||
|
||||
二分法的结束条件:跳出循环之前的最后一次循环,left == right, 此时得到 mid == left,因此:
|
||||
|
||||
- 如果mid > x * mid,则 x 的平方根必然为比left略小一点的某个值,所以最后结果返回 left - 1
|
||||
|
||||
- 如果mid <= x * mid, 则 x 的平方根必然为比left略大一点某个值,又因为执行了 left = mid +1, 所以最后结果返回 left - 1
|
||||
|
||||
"""
|
||||
if x < 2:
|
||||
return x
|
||||
left, right = 1, x // 2
|
||||
while left <= right:
|
||||
mid = left + (right - left) // 2
|
||||
if mid > x / mid:
|
||||
right = mid - 1
|
||||
else:
|
||||
left = mid + 1
|
||||
return left - 1
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
solution = Solution()
|
||||
print(solution.mySqrt(9))
|
||||
print(solution.mySqrt(8))
|
||||
print(solution.mySqrt(10))
|
||||
print(solution.mySqrt(7))
|
||||
@@ -0,0 +1,42 @@
|
||||
#!/usr/bin/env python
|
||||
# coding=utf-8
|
||||
|
||||
class Solution:
|
||||
|
||||
################################################
|
||||
#### 解法一
|
||||
################################################
|
||||
def twoSum(self, nums, target):
|
||||
"""
|
||||
(Knowledge)
|
||||
1. 对每个值tmp,判断 target - tmp 是否在其右边的剩余数组当中
|
||||
2. 如果找到对应的匹配值,则返回两者的位置
|
||||
"""
|
||||
for i in range(len(nums)):
|
||||
tmp = nums[i]
|
||||
remain = nums[i + 1:]
|
||||
if target - tmp in remain:
|
||||
return [i, remain.index(target - tmp) + i + 1]
|
||||
|
||||
|
||||
################################################
|
||||
#### 解法2
|
||||
################################################
|
||||
def twoSum2(self, nums, target):
|
||||
"""
|
||||
(Knowledge)
|
||||
1. 用一个字典记录已经访问过的值及其下标
|
||||
2. 如果访问到某个值num[i]是,发现其匹配值target - nums[i] 出现在dict里面,表示其左边有一个是可以与nums[i]想加得target,
|
||||
此时返回[dict[nums[i]], i]即为结果
|
||||
"""
|
||||
dict = {}
|
||||
for i in range(len(nums)):
|
||||
if target - nums[i] not in dict:
|
||||
dict[nums[i]] = i
|
||||
else:
|
||||
return [dict[target - nums[i]], i]
|
||||
|
||||
if __name__ == '__main__':
|
||||
solution = Solution()
|
||||
print(solution.twoSum([2, 7, 11, 15], 9))
|
||||
print(solution.twoSum2([2, 7, 11, 15], 9))
|
||||
@@ -0,0 +1,89 @@
|
||||
#!/usr/bin/env python
|
||||
# coding=utf-8
|
||||
|
||||
############################################################################
|
||||
# 乱序字符串检查
|
||||
#
|
||||
# 乱序字符串是指一个字符串只是另一个字符串的重新排列。例如,'heart' 和 'earth' 就是乱序字符串。
|
||||
# 'python' 和'typhon' 也是。
|
||||
#
|
||||
# 为了简单起见,我们假设所讨论的两个字符串具有相等的长度,并且他们由26个小写字母集合组成。
|
||||
# 我们的目标是写一个布尔函数,它将两个字符串做参数并返回它们是不是乱序。
|
||||
############################################################################
|
||||
|
||||
|
||||
class Solution:
|
||||
|
||||
###################################################
|
||||
# 此处省略逐字比较,麻烦性能还差,主要是太多难记2333
|
||||
###################################################
|
||||
|
||||
def anagramSolution(self, s1, s2):
|
||||
"""
|
||||
排序对比法
|
||||
|
||||
思路:
|
||||
1. 将两个字符串转为list;
|
||||
2. 堆两个list进行排序;
|
||||
3. 然后注意比较对应位置的字符是否相等即可
|
||||
"""
|
||||
# 特判字符串长度不相同的情况
|
||||
# 其实这个不是必须的,只是在输入有可能长度不一的情况下,用这个可能可以提高一点性能
|
||||
if len(s1) != len(s2):
|
||||
return False
|
||||
list1 = list(s1)
|
||||
list2 = list(s2)
|
||||
list1.sort()
|
||||
list2.sort()
|
||||
|
||||
for i in range(len(list1)):
|
||||
if list1[i] != list2[i]:
|
||||
return False
|
||||
return True
|
||||
|
||||
def anagramSolution2(self, s1, s2):
|
||||
"""
|
||||
字符统计对比法(Knowledge)
|
||||
|
||||
思路:
|
||||
1. 创建两个长度位26的数组;
|
||||
2. 各自统计两个字符串中每个字符出现的次数;
|
||||
3. 接着对比两个数组即可
|
||||
|
||||
PS: ord => python中的一个内置函数,传入一个字符,会返回其对应的ASCII值
|
||||
"""
|
||||
# 特判字符串长度不相同的情况
|
||||
# 其实这个不是必须的,只是在输入有可能长度不一的情况下,用这个可能可以提高一点性能
|
||||
if len(s1) != len(s2):
|
||||
return False
|
||||
|
||||
c1 = [0] * 26
|
||||
c2 = [0] * 26
|
||||
|
||||
# 统计字符出现的次数
|
||||
for i in range(len(s1)):
|
||||
c1[ord(s1[i]) - ord('a')] += 1
|
||||
c2[ord(s1[i]) - ord('a')] += 1
|
||||
|
||||
# 对比统计结果
|
||||
for i in range(26):
|
||||
if c1[i] != c2[i]:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
solution = Solution()
|
||||
|
||||
print(solution.anagramSolution("heart", "earth"), " == True")
|
||||
print(solution.anagramSolution("python", "typhon"), " == True")
|
||||
print(solution.anagramSolution("qwert", "qwertg"), " == False")
|
||||
|
||||
print(solution.anagramSolution2("heart", "earth"), " == True")
|
||||
print(solution.anagramSolution2("python", "typhon"), " == True")
|
||||
print(solution.anagramSolution2("qwert", "qwertg"), " == False")
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
#!/usr/bin/env python
|
||||
# coding=utf-8
|
||||
|
||||
############################################################
|
||||
# Z 字形变换
|
||||
# 将一个给定字符串根据给定的行数,以从上往下、从左到右进行 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
|
||||
############################################################
|
||||
|
||||
import collections
|
||||
|
||||
class Solution:
|
||||
def convert(self, s, numRows):
|
||||
"""
|
||||
:type s: str
|
||||
:type numRows: int
|
||||
:rtype: str
|
||||
|
||||
(Knowledge)
|
||||
|
||||
算法思路:
|
||||
|
||||
1. 用numRows个list记录每行的字符串;
|
||||
|
||||
2. 然后顺序遍历字符串,按Z字形顺序放到合适的行中;
|
||||
|
||||
3. 最后将每行的字符串拼接即可
|
||||
"""
|
||||
if numRows == 1:
|
||||
return s
|
||||
|
||||
lines = [[] for i in range(numRows)]
|
||||
|
||||
# 当前的方向(首先向下,触底向上,触顶向下,依次改变方向)
|
||||
goDown = True
|
||||
|
||||
# 下一个字符要写入的行号,初始为0,根据方向进行更新,向下则+1,向上则-1
|
||||
lineNumber = 0
|
||||
|
||||
# 依次遍历字符串,按Z字型顺序写到合适的行
|
||||
for i in range(len(s)):
|
||||
lines[lineNumber].append(s[i])
|
||||
|
||||
# 判断是否需要改变方向
|
||||
if goDown and lineNumber == numRows - 1:
|
||||
goDown = False
|
||||
if not goDown and lineNumber == 0:
|
||||
goDown = True
|
||||
|
||||
# 根据当前的方向更新行号
|
||||
lineNumber = lineNumber + 1 if goDown else lineNumber - 1
|
||||
|
||||
# 将所有numRows个list拼接成一个list
|
||||
for i in range(1, numRows):
|
||||
lines[0] += lines[i]
|
||||
|
||||
# 将list转字符串返回
|
||||
return "".join(lines[0])
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
solution = Solution()
|
||||
print(solution.convert("LEETCODEISHIRING", 3), "= \nLCIRETOESIIGEDHN")
|
||||
print(solution.convert("LEETCODEISHIRING", 4), "= \nLDREOEIIECIHNTSG")
|
||||
@@ -0,0 +1,69 @@
|
||||
#!/usr/bin/env python
|
||||
# coding=utf-8
|
||||
|
||||
###############################################################
|
||||
# Leetcode 66 加一
|
||||
# https://leetcode-cn.com/problems/plus-one/
|
||||
#
|
||||
# 给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一。
|
||||
# 最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。
|
||||
# 你可以假设除了整数 0 之外,这个整数不会以零开头。
|
||||
#
|
||||
# 示例 1:
|
||||
# 输入: [1,2,3]
|
||||
# 输出: [1,2,4]
|
||||
# 解释: 输入数组表示数字 123。
|
||||
#
|
||||
# 示例 2:
|
||||
# 输入: [4,3,2,1]
|
||||
# 输出: [4,3,2,2]
|
||||
# 解释: 输入数组表示数字 4321。
|
||||
###############################################################
|
||||
|
||||
|
||||
from typing import List
|
||||
|
||||
class Solution:
|
||||
def plusOne(self, digits: List[int]) -> List[int]:
|
||||
"""
|
||||
|
||||
(Knowledge)
|
||||
|
||||
算法思路:
|
||||
1. 从最末尾开始遍历;
|
||||
2. 堆当前元素+1,不足10则结束,满10则执行进位
|
||||
=> 进位就将当前元素值置为0,然后下标左移,继续判断
|
||||
|
||||
3. 如果遍历到头元素了还有进位,则需要在头元素之前插入一个元素,值为1
|
||||
"""
|
||||
|
||||
# 特判空数组的情况
|
||||
if len(digits) == 0:
|
||||
return [1]
|
||||
|
||||
needAdd = False
|
||||
for i in range(len(digits) - 1, -1, -1):
|
||||
digits[i] += 1
|
||||
if digits[i] == 10:
|
||||
digits[i] = 0
|
||||
needAdd = True
|
||||
else:
|
||||
needAdd = False
|
||||
break
|
||||
|
||||
if needAdd:
|
||||
digits.insert(0, 1)
|
||||
|
||||
return digits
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
solution = Solution()
|
||||
|
||||
print(solution.plusOne([1, 2, 3]), "= [1, 2, 4]")
|
||||
print(solution.plusOne([4, 3, 2, 1]), "= [4, 3, 2, 2]")
|
||||
print(solution.plusOne([9, 9, 9]), "= [1, 0, 0, 0]")
|
||||
print(solution.plusOne([9]), "= [1, 0]")
|
||||
print(solution.plusOne([8, 9, 9, 9]), "= [9, 0, 0, 0]")
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
#!/usr/bin/env python
|
||||
# coding=utf-8
|
||||
|
||||
##########################################################
|
||||
# Leetcode 13 罗马数字转整数
|
||||
#
|
||||
# 罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。
|
||||
# 字符 数值
|
||||
# I 1
|
||||
# V 5
|
||||
# X 10
|
||||
# L 50
|
||||
# C 100
|
||||
# D 500
|
||||
# M 1000
|
||||
#
|
||||
# 例如, 罗马数字 2 写做 II ,即为两个并列的 1。12 写做 XII ,即为 X + II 。 27 写做 XXVII, 即为 XX + V + II 。
|
||||
#
|
||||
# 通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。
|
||||
# 同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:
|
||||
# - I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。
|
||||
# - X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。
|
||||
# - C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。
|
||||
#
|
||||
# 给定一个罗马数字,将其转换成整数。输入确保在 1 到 3999 的范围内。
|
||||
#
|
||||
# 示例 1:
|
||||
# 输入: "III"
|
||||
# 输出: 3
|
||||
#
|
||||
# 示例 2:
|
||||
# 输入: "IV"
|
||||
# 输出: 4
|
||||
#
|
||||
# 示例 3:
|
||||
# 输入: "IX"
|
||||
# 输出: 9
|
||||
#
|
||||
# 示例 4:
|
||||
# 输入: "LVIII"
|
||||
# 输出: 58
|
||||
# 解释: L = 50, V= 5, III = 3.
|
||||
#
|
||||
# 示例 5:
|
||||
# 输入: "MCMXCIV"
|
||||
# 输出: 1994
|
||||
# 解释: M = 1000, CM = 900, XC = 90, IV = 4.
|
||||
##########################################################
|
||||
|
||||
|
||||
myMap = {'I': 1, 'V': 5, 'X': 10, 'L': 50, 'C': 100, 'D': 500, 'M': 1000}
|
||||
|
||||
class Solution:
|
||||
def romanToInt(self, s: str) -> int:
|
||||
"""
|
||||
|
||||
(Knowledge)
|
||||
|
||||
思路:
|
||||
1. 首先用map记录罗马字符和对应数值的映射关系;
|
||||
2. 接着每遍历一个字符,就将其对应的值加到结果里面;
|
||||
3. 每轮遍历的时候,如果是 'I', 'X', 'C' 字符,则判断其右边是否有能和其搭配使用的特殊值,如果有则减去两倍的对应数值
|
||||
"""
|
||||
result = 0
|
||||
length = len(s)
|
||||
for i in range(length):
|
||||
result += myMap[s[i]]
|
||||
if s[i] == 'I' and i < length - 1 and (s[i + 1] == 'V' or s[i + 1] == 'X'):
|
||||
result -= (2 * 1)
|
||||
if s[i] == 'X' and i < length - 1 and (s[i + 1] == 'L' or s[i + 1] == 'C'):
|
||||
result -= (2 * 10)
|
||||
if s[i] == 'C' and i < length - 1 and (s[i + 1] == 'D' or s[i + 1] == 'M'):
|
||||
result -= (2 * 100)
|
||||
return result
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
solution = Solution()
|
||||
print(solution.romanToInt("III"), "= 3")
|
||||
print(solution.romanToInt("IV"), "= 4")
|
||||
print(solution.romanToInt("IX"), "= 9")
|
||||
print(solution.romanToInt("LVIII"), "= 58")
|
||||
print(solution.romanToInt("MCMXCIV"), "= 1994")
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
#!/usr/bin/env python
|
||||
# coding=utf-8
|
||||
|
||||
|
||||
################################################################
|
||||
# LeetCode: 69 Sqrt(x)
|
||||
# Implement int sqrt(int x).
|
||||
# Compute and return the square root of x, where x is guaranteedto be a non-negative integer.
|
||||
# Since the return type is an integer, the decimal digits aretruncated and only the integer part of the result is returned.
|
||||
################################################################
|
||||
|
||||
import math
|
||||
|
||||
class Solution:
|
||||
def mySqrt(self, x):
|
||||
"""
|
||||
(Knowledge)
|
||||
|
||||
函数功能描述: 传入一个数字,返回其平方根的整数部分
|
||||
|
||||
思路:
|
||||
1. 首先用特判,处理掉x=1的特殊情况;
|
||||
2. 接着用二分法,找到x平方根的整数部分;
|
||||
|
||||
二分法的结束条件:跳出循环之前的最后一次循环,left == right, 此时得到 mid == left,因此:
|
||||
|
||||
- 如果mid > x * mid,则 x 的平方根必然为比left略小一点的某个值,所以最后结果返回 left - 1
|
||||
|
||||
- 如果mid <= x * mid, 则 x 的平方根必然为比left略大一点某个值,又因为执行了 left = mid +1, 所以最后结果返回 left - 1
|
||||
|
||||
"""
|
||||
if x < 2:
|
||||
return x
|
||||
left, right = 1, x // 2
|
||||
while left <= right:
|
||||
mid = left + (right - left) // 2
|
||||
if mid > x / mid:
|
||||
right = mid - 1
|
||||
else:
|
||||
left = mid + 1
|
||||
return left - 1
|
||||
|
||||
def mySqrt2(self, x):
|
||||
"""
|
||||
(Knowledge)
|
||||
|
||||
算法说明:使用牛顿迭代法,近似求平方根
|
||||
牛顿迭代法求平方跟的证明详见 => https://www.cnblogs.com/upcan/p/9907402.html
|
||||
|
||||
最终得到迭代公式: next = 1/2 * (next + input / next)
|
||||
- next => 等式左边为下一个近似值,等式右的next表示上一个近似值
|
||||
- input => 输入值
|
||||
"""
|
||||
|
||||
# 首先猜测一个初始的预测值
|
||||
next = x / 2
|
||||
|
||||
# 运行20次迭代(这个迭代次数取决于需要的精度,迭代次数越多,得到的结果越精确)
|
||||
for k in range(20):
|
||||
next = 1 / 2 * (next + x / next)
|
||||
|
||||
# 根据题意,进行向下取整
|
||||
return math.floor(next)
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
solution = Solution()
|
||||
print(solution.mySqrt(9))
|
||||
print(solution.mySqrt(8))
|
||||
print(solution.mySqrt(10))
|
||||
print(solution.mySqrt(7))
|
||||
print(solution.mySqrt2(9))
|
||||
print(solution.mySqrt2(8))
|
||||
print(solution.mySqrt2(10))
|
||||
print(solution.mySqrt2(7))
|
||||
@@ -0,0 +1,71 @@
|
||||
#!/usr/bin/env python
|
||||
# coding=utf-8
|
||||
|
||||
#################################################################
|
||||
# Leetcode 141 环形链表
|
||||
#
|
||||
# https://leetcode-cn.com/problems/linked-list-cycle/
|
||||
#
|
||||
# 给定一个链表,判断链表中是否有环。
|
||||
# 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
|
||||
#
|
||||
# 示例 1:
|
||||
# 输入:head = [3,2,0,-4], pos = 1
|
||||
# 输出:true
|
||||
# 解释:链表中有一个环,其尾部连接到第二个节点。
|
||||
#
|
||||
# 示例 2:
|
||||
# 输入:head = [1,2], pos = 0
|
||||
# 输出:true
|
||||
# 解释:链表中有一个环,其尾部连接到第一个节点。
|
||||
#
|
||||
# 示例 3:
|
||||
# 输入:head = [1], pos = -1
|
||||
# 输出:false
|
||||
# 解释:链表中没有环。
|
||||
#
|
||||
# PS: 本题实例部分leetcode上有图解,直接看文字比较抽象,可以点击上面的链接查看
|
||||
#################################################################
|
||||
|
||||
|
||||
|
||||
class ListNode:
|
||||
def __init__(self, x):
|
||||
self.val = x
|
||||
self.next = None
|
||||
|
||||
def __repr__(self):
|
||||
if self:
|
||||
return "{}->{}".format(self.val, repr(self.next))
|
||||
|
||||
|
||||
class Solution:
|
||||
def hasCycle(self, head):
|
||||
"""
|
||||
|
||||
(knowledge)
|
||||
|
||||
思路:
|
||||
1. 可以用快慢指针(快指针一次走两步,慢指针一次走一步);
|
||||
2. 如果快指针率先到达链表尾,则表示链表没有环路;
|
||||
3. 如果快指针走若干步后和慢指针相遇,则表示链表肯定有环路。
|
||||
|
||||
PS: https://labuladong.gitbook.io/algo/suan-fa-si-wei-xi-lie/shuang-zhi-zhen-ji-qiao
|
||||
(这里有对双指针用法的详细总结,包括快慢指针,有图解)
|
||||
"""
|
||||
low, fast = head, head
|
||||
while fast and fast.next:
|
||||
low, fast = low.next, fast.next.next
|
||||
if low == fast:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
solution = Solution()
|
||||
head = ListNode(3)
|
||||
head.next = ListNode(2)
|
||||
head.next.next = ListNode(0)
|
||||
head.next.next.next = ListNode(4)
|
||||
head.next.next.next = head.next
|
||||
print(solution.hasCycle(head), "= True")
|
||||
@@ -0,0 +1,70 @@
|
||||
#!/usr/bin/env python
|
||||
# coding=utf-8
|
||||
|
||||
###########################################################################
|
||||
# Leetcode 20 有效的括号
|
||||
#
|
||||
# 给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。
|
||||
# 有效字符串需满足:
|
||||
# 1. 左括号必须用相同类型的右括号闭合。
|
||||
# 2. 左括号必须以正确的顺序闭合。
|
||||
# 注意空字符串可被认为是有效字符串。
|
||||
#
|
||||
# 示例 1:
|
||||
# 输入: "()"
|
||||
# 输出: true
|
||||
#
|
||||
# 示例 2:
|
||||
# 输入: "()[]{}"
|
||||
# 输出: true
|
||||
#
|
||||
# 示例 3:
|
||||
# 输入: "(]"
|
||||
# 输出: false
|
||||
#
|
||||
# 示例 4:
|
||||
# 输入: "([)]"
|
||||
# 输出: false
|
||||
#
|
||||
# 示例 5:
|
||||
# 输入: "{[]}"
|
||||
# 输出: true
|
||||
###########################################################################
|
||||
|
||||
class Solution:
|
||||
def isValid(self, s):
|
||||
"""
|
||||
|
||||
(knowledge)
|
||||
|
||||
思路:
|
||||
1. 用栈,遇到左括号就推入栈;
|
||||
2. 遇到右括号就比对栈顶的括号和其是否匹配;
|
||||
- 不匹配则返回False
|
||||
- 匹配则将栈顶弹出
|
||||
- 如果此时栈为空,则返回False
|
||||
3. 循环2直至遍历完成,最后,如果栈不为空则返回False,否则返回True
|
||||
|
||||
"""
|
||||
# 这边用list来模拟栈
|
||||
stack = []
|
||||
|
||||
# 一个字典,用来记录括号映射
|
||||
dict = {'(': ')', '{': '}', '[': ']'}
|
||||
|
||||
for c in s:
|
||||
if c in dict:
|
||||
stack.append(c)
|
||||
elif len(stack) == 0 or dict[stack.pop()] != c:
|
||||
return False
|
||||
return len(stack) == 0
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
solution = Solution()
|
||||
print(solution.isValid("()"), "= True")
|
||||
print(solution.isValid("()[]{}"), "= True")
|
||||
print(solution.isValid("(]"), "= False")
|
||||
print(solution.isValid("([)]"), "= False")
|
||||
print(solution.isValid("{()}"), "= True")
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
#!/usr/bin/env python
|
||||
# coding=utf-8
|
||||
|
||||
#################################################################################################
|
||||
# Leetcode 232 用栈实现队列
|
||||
#
|
||||
# 使用栈实现队列的下列操作:
|
||||
# push(x) -- 将一个元素放入队列的尾部。
|
||||
# pop() -- 从队列首部移除元素。
|
||||
# peek() -- 返回队列首部的元素。
|
||||
# empty() -- 返回队列是否为空。
|
||||
#
|
||||
# 示例:
|
||||
# MyQueue queue = new MyQueue();
|
||||
#
|
||||
# queue.push(1);
|
||||
# queue.push(2);
|
||||
# queue.peek(); // 返回 1
|
||||
# queue.pop(); // 返回 1
|
||||
# queue.empty(); // 返回 false
|
||||
#
|
||||
# 说明:
|
||||
# 你只能使用标准的栈操作 -- 也就是只有 push to top, peek/pop from top, size, 和 is empty 操作是合法的。
|
||||
# 你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。
|
||||
# 假设所有操作都是有效的 (例如,一个空的队列不会调用 pop 或者 peek 操作)。
|
||||
#################################################################################################
|
||||
|
||||
|
||||
class MyQueue:
|
||||
"""
|
||||
|
||||
(knowledge)
|
||||
|
||||
思路:
|
||||
1. 使用两个栈来模拟实现队列,分别为stack1和stack2;
|
||||
2. 对于push操作 => 简单将其推到stack1即可;
|
||||
3. 对于peek操作 => 判断stack2是否为空,不为空则返回其栈顶元素,为空则将stack1依次弹栈,并依次push进stack2中,然后返回stack2的栈顶元素;
|
||||
4. 对于pop操作 => 首先执行peek操作,然后弹出stack2的栈顶元素;
|
||||
5. 对于empty操作 => 判断stack1和stack2是否同时为空即可;
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
"""
|
||||
Initialize your data structure here.
|
||||
"""
|
||||
# 使用两个栈来实现一个队列
|
||||
self.stack1, self.stack2 = [], []
|
||||
|
||||
|
||||
def push(self, x):
|
||||
"""
|
||||
Push element x to the back of queue.
|
||||
"""
|
||||
self.stack1.append(x)
|
||||
|
||||
|
||||
def pop(self):
|
||||
"""
|
||||
Removes the element from in front of queue and returns that element.
|
||||
"""
|
||||
self.peek()
|
||||
return self.stack2.pop()
|
||||
|
||||
|
||||
def peek(self):
|
||||
"""
|
||||
Get the front element.
|
||||
"""
|
||||
if not self.stack2:
|
||||
while self.stack1:
|
||||
self.stack2.append(self.stack1.pop())
|
||||
return self.stack2[-1]
|
||||
|
||||
|
||||
def empty(self):
|
||||
"""
|
||||
Returns whether the queue is empty.
|
||||
"""
|
||||
return not self.stack1 and not self.stack2
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
obj = MyQueue()
|
||||
obj.push(1)
|
||||
obj.push(2)
|
||||
param_2 = obj.peek()
|
||||
print(param_2, "= 1")
|
||||
param_3 = obj.pop()
|
||||
print(param_3, "= 1")
|
||||
param_4 = obj.empty()
|
||||
print(param_4, "= False")
|
||||
@@ -0,0 +1,63 @@
|
||||
#!/usr/bin/env python
|
||||
# coding=utf-8
|
||||
|
||||
#######################################################################################
|
||||
# Leetcode 239 滑动窗口最大值
|
||||
#
|
||||
# 给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
|
||||
# 返回滑动窗口中的最大值。
|
||||
#
|
||||
# 进阶:
|
||||
# 你能在线性时间复杂度内解决此题吗?
|
||||
#
|
||||
# 示例:
|
||||
# 输入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3
|
||||
# 输出: [3,3,5,5,6,7]
|
||||
# 解释:
|
||||
#
|
||||
# 滑动窗口的位置 最大值
|
||||
# --------------- -----
|
||||
# [1 3 -1] -3 5 3 6 7 3
|
||||
# 1 [3 -1 -3] 5 3 6 7 3
|
||||
# 1 3 [-1 -3 5] 3 6 7 5
|
||||
# 1 3 -1 [-3 5 3] 6 7 5
|
||||
# 1 3 -1 -3 [5 3 6] 7 6
|
||||
# 1 3 -1 -3 5 [3 6 7] 7
|
||||
#
|
||||
# 提示:
|
||||
# 1 <= nums.length <= 10^5
|
||||
# -10^4 <= nums[i] <= 10^4
|
||||
# 1 <= k <= nums.length
|
||||
#######################################################################################
|
||||
|
||||
import collections
|
||||
|
||||
class Solution:
|
||||
def def maxSlidingWindow(self, nums, k):
|
||||
"""
|
||||
|
||||
(knowledge)
|
||||
|
||||
思路:
|
||||
1. 用一个队列记录当前处于窗口内的值,这个队列有如下性质:
|
||||
- 队列中的元素不会超过窗口大小k;
|
||||
- 保证队头的元素总是队列里面最大的;
|
||||
2. 每次有数据入队时都执行如下流程:
|
||||
- 判断当前队列长度是否为k,如果是则首先pop一个元素,并依次比对,进行若干次出队,把当前队列的最大值排到队首;
|
||||
- 然后将队首元素与预入队元素比对,如果小于等于将要入队的元素,则出队;
|
||||
- 循环执行上一步骤,直到队列为空或者队首元素大于将要入队的元素;
|
||||
- 最后将要入队的元素入队。
|
||||
3. 初始是,先用步骤2的方法,入队k-1个元素,从第k个元素开始,每次入队完,队首的元素即为当前窗口的最大值。
|
||||
|
||||
|
||||
PS: 关于上述算法的流程,这边有一个leetcode官方制作的动画演示:https://leetcode-cn.com/problems/sliding-window-maximum/solution/shi-pin-jie-xi-shuang-duan-dui-lie-hua-dong-chuang/
|
||||
"""
|
||||
|
||||
# 特判,当数组小于等于窗口大小时,不需要滑动,直接返回数组的最大值即可
|
||||
if len(nums) <= k:
|
||||
return max(nums):
|
||||
|
||||
# queue用来存储当前窗口的元素(不一定是全部元素,窗口内最大值以左的元素都出队了)
|
||||
# res用来存储最终的结果(每个窗口的最大值)
|
||||
queue, res = collections.deque(), []
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
#!/usr/bin/env python
|
||||
# coding=utf-8
|
||||
|
||||
##############################################################
|
||||
# Leetcode 7 整数反转
|
||||
# https://leetcode-cn.com/problems/reverse-integer/
|
||||
#
|
||||
# 给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。
|
||||
#
|
||||
# 示例 1:
|
||||
# 输入: 123
|
||||
# 输出: 321
|
||||
#
|
||||
# 示例 2:
|
||||
# 输入: -123
|
||||
# 输出: -321
|
||||
#
|
||||
# 示例 3:
|
||||
# 输入: 120
|
||||
# 输出: 21
|
||||
#
|
||||
##############################################################
|
||||
|
||||
INT_MAX_VAL = 2147483647
|
||||
INT_MIN_VAL = -2147483648
|
||||
|
||||
class Solution:
|
||||
def reverse(self, x):
|
||||
"""
|
||||
(Knowledge)
|
||||
|
||||
思路:
|
||||
1. 首先记录输入值的符号(是正数还是负数),然后取其绝对值|x|进行处理
|
||||
2. 接着用一个long型(Python里面的数字完全够大)存储结果;
|
||||
3. 将|x|从个位开始向左遍历,依次叠加到结果里面;
|
||||
4. 最后判断结果是否移出(与32位有符号整形的最大值和最小值进行比对)
|
||||
"""
|
||||
isNegitive = -1 if x < 0 else 1
|
||||
result, x = 0, abs(x)
|
||||
while x > 0:
|
||||
result = result * 10 + x % 10
|
||||
x = x // 10
|
||||
result = isNegitive * result
|
||||
|
||||
return 0 if result > INT_MAX_VAL or result < INT_MIN_VAL else result
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
solution = Solution()
|
||||
print(solution.reverse(123), "= 321")
|
||||
print(solution.reverse(-123), "= -321")
|
||||
print(solution.reverse(120), "= 21")
|
||||
@@ -0,0 +1,85 @@
|
||||
#!/usr/bin/env python
|
||||
# coding=utf-8
|
||||
|
||||
############################################################
|
||||
# Z 字形变换
|
||||
# 将一个给定字符串根据给定的行数,以从上往下、从左到右进行 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
|
||||
############################################################
|
||||
|
||||
import collections
|
||||
|
||||
class Solution:
|
||||
def convert(self, s, numRows):
|
||||
"""
|
||||
:type s: str
|
||||
:type numRows: int
|
||||
:rtype: str
|
||||
|
||||
(Knowledge)
|
||||
|
||||
算法思路:
|
||||
|
||||
1. 用numRows个list记录每行的字符串;
|
||||
|
||||
2. 然后顺序遍历字符串,按Z字形顺序放到合适的行中;
|
||||
|
||||
3. 最后将每行的字符串拼接即可
|
||||
"""
|
||||
if numRows == 1:
|
||||
return s
|
||||
|
||||
lines = [[] for i in range(numRows)]
|
||||
|
||||
# 当前的方向(首先向下,触底向上,触顶向下,依次改变方向)
|
||||
goDown = True
|
||||
|
||||
# 下一个字符要写入的行号,初始为0,根据方向进行更新,向下则+1,向上则-1
|
||||
lineNumber = 0
|
||||
|
||||
# 依次遍历字符串,按Z字型顺序写到合适的行
|
||||
for i in range(len(s)):
|
||||
lines[lineNumber].append(s[i])
|
||||
|
||||
# 判断是否需要改变方向
|
||||
if goDown and lineNumber == numRows - 1:
|
||||
goDown = False
|
||||
if not goDown and lineNumber == 0:
|
||||
goDown = True
|
||||
|
||||
# 根据当前的方向更新行号
|
||||
lineNumber = lineNumber + 1 if goDown else lineNumber - 1
|
||||
|
||||
# 将所有numRows个list拼接成一个list
|
||||
for i in range(1, numRows):
|
||||
lines[0] += lines[i]
|
||||
|
||||
# 将list转字符串返回
|
||||
return "".join(lines[0])
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
solution = Solution()
|
||||
print(solution.convert("LEETCODEISHIRING", 3), "= \nLCIRETOESIIGEDHN")
|
||||
print(solution.convert("LEETCODEISHIRING", 4), "= \nLDREOEIIECIHNTSG")
|
||||
@@ -0,0 +1,69 @@
|
||||
#!/usr/bin/env python
|
||||
# coding=utf-8
|
||||
|
||||
###############################################################
|
||||
# Leetcode 66 加一
|
||||
# https://leetcode-cn.com/problems/plus-one/
|
||||
#
|
||||
# 给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一。
|
||||
# 最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。
|
||||
# 你可以假设除了整数 0 之外,这个整数不会以零开头。
|
||||
#
|
||||
# 示例 1:
|
||||
# 输入: [1,2,3]
|
||||
# 输出: [1,2,4]
|
||||
# 解释: 输入数组表示数字 123。
|
||||
#
|
||||
# 示例 2:
|
||||
# 输入: [4,3,2,1]
|
||||
# 输出: [4,3,2,2]
|
||||
# 解释: 输入数组表示数字 4321。
|
||||
###############################################################
|
||||
|
||||
|
||||
from typing import List
|
||||
|
||||
class Solution:
|
||||
def plusOne(self, digits: List[int]) -> List[int]:
|
||||
"""
|
||||
|
||||
(Knowledge)
|
||||
|
||||
算法思路:
|
||||
1. 从最末尾开始遍历;
|
||||
2. 堆当前元素+1,不足10则结束,满10则执行进位
|
||||
=> 进位就将当前元素值置为0,然后下标左移,继续判断
|
||||
|
||||
3. 如果遍历到头元素了还有进位,则需要在头元素之前插入一个元素,值为1
|
||||
"""
|
||||
|
||||
# 特判空数组的情况
|
||||
if len(digits) == 0:
|
||||
return [1]
|
||||
|
||||
needAdd = False
|
||||
for i in range(len(digits) - 1, -1, -1):
|
||||
digits[i] += 1
|
||||
if digits[i] == 10:
|
||||
digits[i] = 0
|
||||
needAdd = True
|
||||
else:
|
||||
needAdd = False
|
||||
break
|
||||
|
||||
if needAdd:
|
||||
digits.insert(0, 1)
|
||||
|
||||
return digits
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
solution = Solution()
|
||||
|
||||
print(solution.plusOne([1, 2, 3]), "= [1, 2, 4]")
|
||||
print(solution.plusOne([4, 3, 2, 1]), "= [4, 3, 2, 2]")
|
||||
print(solution.plusOne([9, 9, 9]), "= [1, 0, 0, 0]")
|
||||
print(solution.plusOne([9]), "= [1, 0]")
|
||||
print(solution.plusOne([8, 9, 9, 9]), "= [9, 0, 0, 0]")
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
#!/usr/bin/env python
|
||||
# coding=utf-8
|
||||
|
||||
##########################################################
|
||||
# Leetcode 13 罗马数字转整数
|
||||
#
|
||||
# 罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。
|
||||
# 字符 数值
|
||||
# I 1
|
||||
# V 5
|
||||
# X 10
|
||||
# L 50
|
||||
# C 100
|
||||
# D 500
|
||||
# M 1000
|
||||
#
|
||||
# 例如, 罗马数字 2 写做 II ,即为两个并列的 1。12 写做 XII ,即为 X + II 。 27 写做 XXVII, 即为 XX + V + II 。
|
||||
#
|
||||
# 通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。
|
||||
# 同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:
|
||||
# - I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。
|
||||
# - X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。
|
||||
# - C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。
|
||||
#
|
||||
# 给定一个罗马数字,将其转换成整数。输入确保在 1 到 3999 的范围内。
|
||||
#
|
||||
# 示例 1:
|
||||
# 输入: "III"
|
||||
# 输出: 3
|
||||
#
|
||||
# 示例 2:
|
||||
# 输入: "IV"
|
||||
# 输出: 4
|
||||
#
|
||||
# 示例 3:
|
||||
# 输入: "IX"
|
||||
# 输出: 9
|
||||
#
|
||||
# 示例 4:
|
||||
# 输入: "LVIII"
|
||||
# 输出: 58
|
||||
# 解释: L = 50, V= 5, III = 3.
|
||||
#
|
||||
# 示例 5:
|
||||
# 输入: "MCMXCIV"
|
||||
# 输出: 1994
|
||||
# 解释: M = 1000, CM = 900, XC = 90, IV = 4.
|
||||
##########################################################
|
||||
|
||||
|
||||
myMap = {'I': 1, 'V': 5, 'X': 10, 'L': 50, 'C': 100, 'D': 500, 'M': 1000}
|
||||
|
||||
class Solution:
|
||||
def romanToInt(self, s: str) -> int:
|
||||
"""
|
||||
|
||||
(Knowledge)
|
||||
|
||||
思路:
|
||||
1. 首先用map记录罗马字符和对应数值的映射关系;
|
||||
2. 接着每遍历一个字符,就将其对应的值加到结果里面;
|
||||
3. 每轮遍历的时候,如果是 'I', 'X', 'C' 字符,则判断其右边是否有能和其搭配使用的特殊值,如果有则减去两倍的对应数值
|
||||
"""
|
||||
result = 0
|
||||
length = len(s)
|
||||
for i in range(length):
|
||||
result += myMap[s[i]]
|
||||
if s[i] == 'I' and i < length - 1 and (s[i + 1] == 'V' or s[i + 1] == 'X'):
|
||||
result -= (2 * 1)
|
||||
if s[i] == 'X' and i < length - 1 and (s[i + 1] == 'L' or s[i + 1] == 'C'):
|
||||
result -= (2 * 10)
|
||||
if s[i] == 'C' and i < length - 1 and (s[i + 1] == 'D' or s[i + 1] == 'M'):
|
||||
result -= (2 * 100)
|
||||
return result
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
solution = Solution()
|
||||
print(solution.romanToInt("III"), "= 3")
|
||||
print(solution.romanToInt("IV"), "= 4")
|
||||
print(solution.romanToInt("IX"), "= 9")
|
||||
print(solution.romanToInt("LVIII"), "= 58")
|
||||
print(solution.romanToInt("MCMXCIV"), "= 1994")
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
#!/usr/bin/env python
|
||||
# coding=utf-8
|
||||
|
||||
|
||||
##########################################################
|
||||
# 栈的应用——十进制转二进制
|
||||
##########################################################
|
||||
|
||||
class Stack:
|
||||
def __init__(self):
|
||||
self.items = []
|
||||
|
||||
def isEmpty(self):
|
||||
return self.items == []
|
||||
|
||||
def push(self, item):
|
||||
self.items.append(item)
|
||||
|
||||
def pop(self):
|
||||
return self.items.pop()
|
||||
|
||||
def peek(self):
|
||||
return self.items[len(self.items)-1]
|
||||
|
||||
def size(self):
|
||||
return len(self.items)
|
||||
|
||||
class Solution:
|
||||
def divideBy2(self, decNumber):
|
||||
"""
|
||||
|
||||
(knowledge)
|
||||
|
||||
算法功能说明:传入一个正整数,将其转换为2进制表达方式
|
||||
|
||||
思路:
|
||||
1. 依次除2取余,使用栈保存余数
|
||||
2. 接着依次弹栈,构造出二进制串
|
||||
"""
|
||||
stack = Stack()
|
||||
|
||||
while decNumber > 0:
|
||||
stack.push(decNumber % 2)
|
||||
decNumber = decNumber // 2
|
||||
|
||||
result = ""
|
||||
while not stack.isEmpty():
|
||||
result += str(stack.pop())
|
||||
return result
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
solution = Solution()
|
||||
print(solution.divideBy2(233), "= 11101001")
|
||||
print(solution.divideBy2(42), "= 101010")
|
||||
@@ -0,0 +1,57 @@
|
||||
#!/usr/bin/env python
|
||||
# coding=utf-8
|
||||
|
||||
|
||||
#######################################################################
|
||||
# 队列的应用——烫手山芋问题(约瑟夫问题)
|
||||
#
|
||||
# 据说著名犹太历史学家 Josephus有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,
|
||||
# 39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,
|
||||
# 然后再由下一个重新报数,直到所有人都自杀身亡为止。然而Josephus 和他的朋友并不想遵从。首先从一个人开始,越过k-2个人(因为第一个人已经被越过),
|
||||
# 并杀掉第k个人。接着,再越过k-1个人,并杀掉第k个人。这个过程沿着圆圈一直进行,直到最终只剩下一个人留下,这个人就可以继续活着。
|
||||
# 问题是,给定了和,一开始要站在什么地方才能避免被处决?Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。
|
||||
#######################################################################
|
||||
|
||||
class Queue:
|
||||
def __init__(self):
|
||||
self.items = []
|
||||
|
||||
def isEmpty(self):
|
||||
return self.items == []
|
||||
|
||||
def enqueue(self, item):
|
||||
self.items.insert(0,item)
|
||||
|
||||
def dequeue(self):
|
||||
return self.items.pop()
|
||||
|
||||
def size(self):
|
||||
return len(self.items)
|
||||
|
||||
class Solution:
|
||||
def hotPotato(self, nameList, num):
|
||||
"""
|
||||
|
||||
(knowledge)
|
||||
|
||||
算法功能描述:堆名称列表里的人,每数num个人枪毙一个第num个人
|
||||
|
||||
思路:
|
||||
1. 首先将所有人入队;
|
||||
2. 将前num - 1个人出队,入队,则num个人处于队头位置,直接出队不入队
|
||||
3. 重复2,直至队列为空
|
||||
"""
|
||||
queue = Queue()
|
||||
for name in nameList:
|
||||
queue.enqueue(name)
|
||||
|
||||
while not queue.isEmpty():
|
||||
for i in range(num - 1):
|
||||
queue.enqueue(queue.dequeue())
|
||||
print(queue.dequeue())
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
solution = Solution()
|
||||
solution.hotPotato(["Bill", "David", "Susan", "Jane", "Kent", "Brad"], 7)
|
||||
@@ -0,0 +1,41 @@
|
||||
#!/usr/bin/env python
|
||||
# coding=utf-8
|
||||
|
||||
############################################################
|
||||
# 双向队列的应用——回文检查
|
||||
############################################################
|
||||
|
||||
import collections
|
||||
|
||||
class Solution:
|
||||
def palchecker(self, str):
|
||||
"""
|
||||
算法功能说明:输入一个字符串,返回一个bool值表示该字符串是否是回文
|
||||
|
||||
思路:
|
||||
1. 使用一个双向队列,首先将字符串中的每个字符入队;
|
||||
2. 接着比对队头和队尾两个字符是否相等,相等则头尾同时出队(如果只剩一个元素,出队一次即可),不相等则返回False
|
||||
|
||||
PS: 关于collections的使用 => https://www.liaoxuefeng.com/wiki/1016959663602400/1017681679479008
|
||||
"""
|
||||
# 使用python内置的双向队列实现
|
||||
dqueue = collections.deque()
|
||||
|
||||
# 将所有字符入队
|
||||
for c in str:
|
||||
dqueue.append(c)
|
||||
|
||||
# 依次判断首尾字符是否相同
|
||||
while len(dqueue) > 1:
|
||||
if dqueue.pop() != dqueue.popleft():
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
solution = Solution()
|
||||
print(solution.palchecker("abbba"), "= True")
|
||||
print(solution.palchecker("qwertgtrewq"), "= True")
|
||||
print(solution.palchecker("a"), "= True")
|
||||
print(solution.palchecker("abcbc"), "= False")
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
#!/usr/bin/env python
|
||||
# coding=utf-8
|
||||
|
||||
###########################################################################
|
||||
# Leetcode 206 反转链表
|
||||
#
|
||||
# 反转一个单链表。
|
||||
#
|
||||
# 示例:
|
||||
# 输入: 1->2->3->4->5->NULL
|
||||
# 输出: 5->4->3->2->1->NULL
|
||||
#
|
||||
# 进阶:
|
||||
# 你可以迭代或递归地反转链表。你能否用两种方法解决这道题?
|
||||
###########################################################################
|
||||
|
||||
|
||||
class ListNode:
|
||||
def __init__(self, x):
|
||||
self.val = x
|
||||
self.next = None
|
||||
|
||||
def __repr__(self):
|
||||
if self:
|
||||
return "{}->{}".format(self.val, repr(self.next))
|
||||
|
||||
|
||||
class Solution:
|
||||
def reverseList(self, head):
|
||||
"""
|
||||
|
||||
(knowledge)
|
||||
|
||||
思路:
|
||||
1. 用两个指针,一个指针指向新链(初始为None),一个指向原链(初始为head);
|
||||
2. 从头往后依次遍历,进行反挂
|
||||
"""
|
||||
cur = None
|
||||
while head is not None:
|
||||
head.next, cur, head = cur, head, head.next
|
||||
return cur
|
||||
|
||||
if __name__ == '__main__':
|
||||
head = ListNode(1)
|
||||
head.next = ListNode(2)
|
||||
head.next.next = ListNode(3)
|
||||
head.next.next.next = ListNode(4)
|
||||
head.next.next.next.next = ListNode(5)
|
||||
|
||||
solution = Solution()
|
||||
print(solution.reverseList(head))
|
||||
@@ -0,0 +1,50 @@
|
||||
#!/usr/bin/env python
|
||||
# coding=utf-8
|
||||
|
||||
###############################################################################
|
||||
# Leetcode 24 两两交换链表中的节点
|
||||
#
|
||||
# 给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
|
||||
# 你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
|
||||
###############################################################################
|
||||
|
||||
class ListNode:
|
||||
def __init__(self, x):
|
||||
self.val = x
|
||||
self.next = None
|
||||
|
||||
def __repr__(self):
|
||||
if self:
|
||||
return "{}->{}".format(self.val, repr(self.next))
|
||||
|
||||
|
||||
class Solution:
|
||||
def swapPairs(self, head):
|
||||
"""
|
||||
|
||||
(knowledge)
|
||||
|
||||
思路:
|
||||
1. 用三个指针pre(初始为None),cur(初始为head),next(初始位head.next);
|
||||
2. 接着借由三个指针完成两个节点的交换
|
||||
"""
|
||||
if head is None or head.next is None:
|
||||
return head
|
||||
pre, cur, next, head = None, head, head.next, head.next
|
||||
while cur is not None and next is not None:
|
||||
if pre is not None:
|
||||
pre.next = cur.next
|
||||
cur.next, next.next, cur, pre = next.next, cur, next.next, cur
|
||||
if cur is not None:
|
||||
next = cur.next
|
||||
return head
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
solution = Solution()
|
||||
head = ListNode(1)
|
||||
head.next = ListNode(2)
|
||||
head.next.next = ListNode(3)
|
||||
head.next.next.next = ListNode(4)
|
||||
head.next.next.next.next = ListNode(5)
|
||||
print(solution.swapPairs(head))
|
||||
Reference in New Issue
Block a user