【算法】剑指 Offer 专项突击版 Day2整数部分
题目地址:https://leetcode-cn.com/study-plan/lcof/?progress=wgzvtig
目标:要点总结,分享思路
II 【中等】004. 只出现一次的数字
难度:一般,转化为二进制位考虑就简单了
要点:
- 题型:在顺序表中找出仅出现1次的元素,其余元素均出现N次
- 思路:哈希表统计各元素出现个数,空间复杂度 O ( n ) O(n) O(n);
- 优化:二进制位的计数统计,空间复杂度 O ( 1 ) O(1) O(1)
- 重点:因表中元素大小有限,可将他们考虑成二进制数,统计每位二进制数的和
- 举例:有1,5,5,5这样一组数,二进制表示为
1 = 001
5 = 101
则将每位二进制位求和得 304,各位对3取余得001即仅出现1次的数1
同理,对其他出现N次改为对N取余即可
class Solution:
def singleNumber(self, nums: List[int]) -> int:
# # collection哈希表统计出现次数方法,空间复杂度O(n)
# freq = collections.Counter(nums)
# return [num for num,occ in freq.items() if occ == 1][0]
# 二进制位,空间复杂度O(1)
ans = 0
for i in range(32):
# &位与运算,将每位二进制位与1位与求和得到该二进制位1的个数
total = sum( (num>>i)&1 for num in nums)
if total % 3:
if i == 31: ans-= 1<<31
else:
ans += 1<<i # 也可采用|位或运算,将+=换成|=
return ans
总结:出现次数问题转为二进制数考虑,空间复杂度更低
II 【中等】005. 单词长度的最大乘积
难度:一般,想到one-hot编码就简单了
要点:
- 将词与词的字母比较替换为二进制数字的或运算
- 一图明了,如下,图片摘自题解【花落&月缺】被利用彻底的二进制特性ヾ(=・ω・=)o
class Solution:
def maxProduct(self, words: List[str]) -> int:
nums,lens = [],[]
for word in words:
# 单词one-hot编码
word_num = 0
word_len = 0
for w in word:
# 此处要用|位或,来表示该字母是否出现过
# 不能用+=来表示,这样会导致字母重复后被重复统计
word_num |= 1<<( ord(w) - ord('a') )
word_len += 1
nums.append(word_num)
lens.append(word_len)
res = 0
for num1,len1 in zip(nums,lens):
for num2,len2 in zip(nums,lens):
if (num1&num2) == 0:
res = max(len1 * len2,res)
return res
总结:减法代替除法的过程中,可优化为
被减数 - 减数的倍数,其中倍数用左移考虑
II 【简单】006. 排序数组中两个数字之和
难度:非常简单,双指针快速解决
要点:
- 有序顺序表中两数问题,一般都可以用双指针解决,注意要有序,同时也要根据题目中重复等再加判断
- 左右指针分别指向表的左右两边,判断求和后比目标值大小即可,大了调右指针变小,小了调左指针变大。
class Solution:
def twoSum(self, numbers: List[int], target: int) -> List[int]:
left,right = 0,len(numbers)-1
while left<right:
if numbers[left]+numbers[right] > target:
right -= 1
elif numbers[left]+numbers[right] < target:
left += 1
else:
return [left,right]
总结:双指针简单明了