一、数组
136. 只出现一次的数字 - 力扣(LeetCode)
from functools import reduce
def singleNumber(nums):
return reduce(lambda x, y: x ^ y, nums)
if __name__ == '__main__':
array = list(map(int, input().split()))
print(array)
s_n = singleNumber(array)
print(s_n)
知识点:位运算
&、|、^、~、>>、<<
在计算机中都是以二进制来进行运算,在代码中直接使用(+、-、*、/)运算符,合理的运用位运算更能显著提高代码在机器上的执行效率。
位运算(&、|、^、~、>>、 | 菜鸟教程 (runoob.com)
189. 轮转数组 - 力扣(LeetCode)
要用nums[:]原地更改,同时考虑到k大于len(nums)的情况,所以要取余
nums和nums[:]的区别在于它们指向的对象不同,nums是列表对象的引用,nums[:]是对列表nums的元素的引用
方法一:
时间复杂度:O(n)
空间复杂度:O(n)
def rotate(nums, k):
# 取余很必要
k = k % len(nums)
nums[:] = nums[-k:] + nums[:-k]
return nums
if __name__ == '__main__':
nums = list(map(int, input().split(',')))
k = int(input())
array = rotate(nums, k)
print(array)
方法二:
时间复杂度:O(n*k)
空间复杂度:O(1)
# 12.75%
def rotate_list(nums, k):
for i in range(k):
nums.insert(0, nums.pop())
return nums
方法三:
时间复杂度:
空间复杂度:O(1)
# 58.65%
def rotate(nums, k):
k = k % len(nums)
reverse(nums, 0, len(nums) - 1)
print(nums)
reverse(nums, 0, k - 1)
print(nums)
reverse(nums, k, len(nums) - 1)
print(nums)
def reverse(nums, start, end):
while start < end:
nums[start], nums[end] = nums[end], nums[start]
start += 1
end -= 1
列表的操作
pythonic、生成器表达式(generator expression)
https://zhuanlan.zhihu.com/p/54011712
https://zhuanlan.zhihu.com/p/503164110
内置操作的时间复杂度
350. 两个数组的交集 II - 力扣(LeetCode)
方法一:
时间复杂度:O(m+n)
空间复杂度:O(min(m,n))
import collections
# 52.04%
def intersect(nums1, nums2):
"""
:type nums1: List[int]
:type nums2: List[int]
:rtype: List[int]
"""
if len(nums1) > len(nums2):
return intersect(nums2, nums1)
h = collections.Counter()
for n1 in nums1:
h[n1] += 1
result = []
for n2 in nums2:
if h.get(n2, 0) > 0:
result.append(n2)
h[n2] -= 1
if h[n2] == 0:
del h[n2]
return result
if __name__ == '__main__':
num1 = list(map(int, input().split(',')))
num2 = list(map(int, input().split(',')))
result = intersect(num1, num2)
print(result)
方法二:
时间复杂度:O(mlogm + nlogn)
空间复杂度:O(min(m,n))
# 74.21%
def intersect_sort(num1, num2):
num1.sort()
num2.sort()
i, j = 0, 0
result = []
while i < len(num1) and j < len(num2):
if num1[i] < num2[j]:
i += 1
elif num1[i] > num2[j]:
j += 1
elif num1[i] == num2[j]:
result.append(num1[i])
i += 1
j += 1
return result
哈希表/散列表:根据键(Key)直接访问在内存储存位置的数据结构
作用:实现数据到存储位置的一对一映射
collections.Counter:用于计数 hashable对象的字典子类
详解Python计数的Counter类 https://zhuanlan.zhihu.com/p/355601478
1. 两数之和 - 力扣(LeetCode)
方法一:暴力解法
时间复杂度:O(n^2)
空间复杂度:O(1)
def twoSum(nums, target):
length = len(nums)
for i in range(length):
for j in range(length):
if (i != j) and (nums[i] + nums[j] == target):
return [i, j]
if __name__ == '__main__':
nums = list(map(int, input().split(',')))
target = int(input())
result = twoSum(nums, target)
print(result)
方法二:
时间复杂度:O(n)
空间复杂度:O(n)
# 98.80%
def twoSum_Hash(nums, target):
hashtable = dict()
for i, num in enumerate(nums):
if target - num in hashtable:
return [hashtable[target - num], i]
hashtable[nums[i]] = i
return []
哈希表
26. 删除有序数组中的重复项 题解 - 力扣(LeetCode)
def removeDuplicates(nums):
"""
:type nums: List[int]
:rtype: int
"""
i, j = 0, 0
length = len(nums)
result = []
while i < length:
if j < length and nums[i] == nums[j]:
j += 1
else:
result.append(nums[i])
i = j
nums[:] = result
return len(result)
if __name__ == '__main__':
nums = list(map(int, input().split(',')))
len = removeDuplicates(nums)
print(len)
# 91.92%
def removeDuplicates(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
i, j = 0, 1
length = len(nums)
while j < length:
if nums[i] == nums[j]:
j += 1
else:
nums[i + 1] = nums[j]
i += 1
return i + 1
二、字符串
344. 反转字符串 - 力扣(LeetCode)
def reverseString(s):
"""
:type s: List[str]
:rtype: None Do not return anything, modify s in-place instead.
"""
for i in range(len(s) >> 1):
s[i], s[- i - 1] = s[- i - 1], s[i]
if __name__ == '__main__':
s = input().split(',')
reverseString(s)
print(s)
python列表的两种索引方式、>>运算符、直接a,b=b,a交换更快
387. 字符串中的第一个唯一字符 - 力扣(LeetCode)
方法一:
时间复杂度:O(n)
空间复杂度:O(∣Σ∣),∣Σ∣≤26
def firstUniqChar(s):
"""
:type s: str
:rtype: int
"""
h = collections.Counter(s)
for i, ch in enumerate(s):
if h.get(ch, 0) == 1:
return i
return -1
if __name__ == '__main__':
s = input()
reuslt = firstUniqChar(s)
print(reuslt)
8. 字符串转换整数 (atoi) - 力扣(LeetCode)
def myAtoi(s):
"""
:type s: str
:rtype: int
"""
res = 0
flag = 1
i = 0
for i in range(len(s)):
if s[i] == ' ':
i = i + 1
elif s[i] == '+':
flag = 1
i = i + 1
break
elif s[i] == '-':
flag = -1
i = i + 1
break
else:
break
for j in range(i, len(s)):
if '0' <= s[j] <= '9':
res = res * 10 + int(s[j])
elif 'a' <= s[j] <= 'z' or 'A' <= s[j] <= 'Z' or s[j] == '.' or s[j] == '+' or s[j] == '-' or s[j] == ' ':
break
res = flag * res
if res < -1 * pow(2, 31):
res = -1 * pow(2, 31)
elif res > pow(2, 31) - 1:
res = pow(2, 31) - 1
return res
if __name__ == '__main__':
s = input()
res = myAtoi(s)
print(res)
方法二:自动机
INT_MAX = 2 ** 31 - 1
INT_MIN = -2 ** 31
class Automaton:
def __init__(self):
self.state = 'start'
self.sign = 1
self.ans = 0
self.table = {
'start': ['start', 'signed', 'in_number', 'end'],
'signed': ['end', 'end', 'in_number', 'end'],
'in_number': ['end', 'end', 'in_number', 'end'],
'end': ['end', 'end', 'end', 'end'],
}
def get_col(self, c):
if c.isspace():
return 0
if c == '+' or c == '-':
return 1
if c.isdigit():
return 2
return 3
def get(self, c):
self.state = self.table[self.state][self.get_col(c)]
if self.state == 'in_number':
self.ans = self.ans * 10 + int(c)
self.ans = min(self.ans, INT_MAX) if self.sign == 1 else min(self.ans, -INT_MIN)
elif self.state == 'signed':
self.sign = 1 if c == '+' else -1
class Solution(object):
def myAtoi(self, s):
"""
:type s: str
:rtype: int
"""
automaton = Automaton()
for c in s:
automaton.get(c)
return automaton.sign * automaton.ans
方法三:正则表达式
def myAtoi(self, s):
"""
:type s: str
:rtype: int
"""
return max(min(int(*re.findall('^[\+\-]?\d+', s.lstrip())), 2 ** 31 - 1), -2 ** 31)
- 使用正则表达式
^:匹配字符串开头,[\+\-]:代表一个+字符或-字符,?:前面一个字符可有可无,\d:一个数字,+:前面一个字符的一个或多个,\D:一个非数字字符
max(min(数字, 2**31 - 1), -2**31)
用来防止结果越界
*代表的传递参数,传递无名参数,你可以搜一下python *的用法
*实际上是对re.findall的结果进行操作。findall函数返回所有找到的结果,用一个list表示,*是解包,因为我们的答案只有一个也就是说list中只会有一个元素,所以直接解包就可以了。解包:[1,2,3]→1,2,3
28. 找出字符串中第一个匹配项的下标 - 力扣(LeetCode)
方法一:暴力求解
# 78.23%
def strStr(haystack, needle):
"""
:type haystack: str
:type needle: str
:rtype: int
"""
i, j = 0, 0
if len(haystack) < len(needle):
return -1
for i in range(len(haystack)):
for j in range(len(needle)):
if i + j > len(haystack) - 1:
return -1
elif haystack[i + j] != needle[j]:
break
elif j >= len(needle) - 1:
return i
return -1
方法二:KMP算法
# 49.74%
def strStr(haystack, needle):
next = getnext(needle)
i, j = 0, 0
while i < len(haystack):
if haystack[i] == needle[j]:
i = i + 1
j = j + 1
elif j > 0:
j = next[j - 1]
else:
i = i + 1
if j >= len(needle):
return i - j
return -1
def getnext(needle):
'''
param needle:
return:
example:
aabaaf
[0, 1, 0, 1, 2, 0]
'''
next = ['' for i in range(len(needle))]
next[0] = k = 0
for i in range(1, len(needle)):
while k > 0 and needle[k] != needle[i]:
k = next[k - 1]
if needle[k] == needle[i]:
k += 1
next[i] = k
return next
if __name__ == '__main__':
haystack = input()
needle = input()
res = strStr(haystack, needle)
print(res)
求解next数组的代码:根据已经掌握的信息规避重复的运算。
三、链表
206. 反转链表 - 力扣(LeetCode)
方法一:三个指针,其实可以优化为两个指针
# 77.63%
def reverseList(head):
"""
:type head: ListNode
:rtype: ListNode
"""
if head == None:
return None
front = head.next
rear = head
rear.next = None
while front != None:
head = front
front = front.next
head.next = rear
rear = head
return head
方法二:两个指针
# 98.83%
def reverseList(head):
"""
:type head: ListNode
:rtype: ListNode
"""
# 申请两个节点,pre和 cur,pre指向None
pre = None
cur = head
# 遍历链表,while循环里面的内容其实可以写成一行
while cur:
# 记录当前节点的下一个节点
tmp = cur.next
# 然后将当前节点指向pre
cur.next = pre
# pre和cur节点都前进一位
pre = cur
cur = tmp
return pre
上面两种感觉差不多
方法三:递归
def reverseList(self, head):
"""
:type head: ListNode
:rtype: LitNode
"""
# 递归终止条件是当前为空,或者下一个节点为空
if(head==None or head.next==None):
return head
# 这里的cur就是最后一个节点
cur = self.reverseList(head.next)
# 这里请配合动画演示理解
# 如果链表是 1->2->3->4->5,那么此时的cur就是5
# 而head是4,head的下一个是5,下下一个是空
# 所以head.next.next 就是5->4
head.next.next = head
# 防止链表循环,需要将head.next设置为空
head.next = None
# 每层递归函数都返回cur,也就是最后一个节点
return cur