Leetcode夜猫赛_32学习笔记

学习来源:

leetcode官方题解
评论区大佬的题解

5468

朴素方法:遍历存储数组中缺失的数字,若K在其中则返回,否则利用数组最后一个数值计算K

tmp = []
# 遍历存储缺失值
for i in range(1,arr[-1]+1):
    if i not in arr:
        tmp.append(i)
# 查找K是否在tmp中
lens = len(tmp)
for i in range(1,lens+1):
    if i == k:
        return tmp[i-1]
# 若不在其中则,利用最后一个值与tmp中的元素个数计算K
return arr[-1] + (k-lens)

分情况讨论优化:缺失数字的位置无非3种位置:数组前,数组范围内和数组之后。因为数组严格递增,所以数组中元素值减去索引再减去1即为当前元素之前缺失的数值个数。

# 缺失数字在数组前
if k <= arr[0] - 1:
	return k
# 缺失数字在数组中
for i in range(len(arr)):
	if arr[i] - i - 1 >= k:
		'''
		若当前arr[i]之前所缺失的数值个数大于K,则首先计算arr[i-1]之前缺失了多少数值
		那么此时arr[i-1]与arr[i]之间缺少了:(k - (arr[i-1] - (i-1) - 1)) 个
		所以所求数值为:arr[i-1] + (k - (arr[i-1] - (i-1) - 1)),化简即为i + k
		'''
		return i + k
# 缺失数字在数组后
return len(arr) + k  # arr[-1] + (k - (arr[-1] - (len(arr)-1) - 1))
5469:K次操作转变字符串

该题首先需要准确理解题意,理解示例的计算过程。
题目解释

  1. 一共有K轮操作机会,每轮操作(假设是第i轮)只能选择:对某一未更改过的字符,修改i次,或者,不修改任何字符
  2. 每次修改,只能是向后替换i次。(a向后替换1次变为b,……,z向后替换1次变为a)`

示例1解释K=9,因此一共有9轮操作机会。字符串s='input'转换为字符串t='ouput',只需将字符i转换6次变为字符o,将字符n转换7次变为字符u,即可。

第1轮:此时要么修改某一未修改过的字符1次,要么不修改。发现字符串s中没有需要修改1次的字符。
第2轮:此时要么修改某一未修改过的字符2次,要么不修改。发现字符串s中没有需要修改2次的字符。
……
第6轮:此时要么修改某一未修改过的字符6次,要么不修改。修改字符i
第7轮:此时要么修改某一未修改过的字符7次,要么不修改。修改字符n

综上,朴素解法不难写出:

lens = len(s)
lent = len(t)
if lens != lent:
    return false
# 记录进行修改的字符
charlist = dict()
# 遍历字符串s
for i in range(lens):
    if ord(t[i]) == ord(s[i]):
        continue
    # 计算需要修该几次,并查看记录中该次数是否已经使用
    res = (ord(t[i]) + 26 - ord(s[i])) % 26
    if res in charlist:
    	# 已经使用,则需要多转换26次
        charlist[res] += 1
        res += charlist[res]*26
    else:
    	# 没有使用,进行记录
        charlist[res] = 0
    # 判断该修改轮次是否可达
    if res > k:
        return false
return true
5470

左右括号匹配,两个右括号可以匹配一个左括号。括号类问题经常使用堆栈来做,本题中其实可以使用一个变量,记录左括号的个数,减少空间使用。

lens = len(s)
ind = 0  # 当前索引
stack = []  # 记录左括号
res = 0  # 最终结果
while ind<lens:
    if s[ind] == '(':  # 遇到左括号就存入
        stack.append(s[ind])
        ind += 1  # 更新索引
    else:
        if ind+1 < lens and s[ind+1] == ')':
            ind += 2  # 若为两个右括号,则完成匹配,索引向后更新2位
        else:
            res += 1  # 加1个右括号,完成匹配,索引只需更新1位
            ind += 1
        # 完成1次匹配,从stack中弹出一个左括号
        if stack:
            stack.pop(-1)
        else:
            res += 1  # 若当前stack中为空,则补全
res += len(stack)*2  # 若左括号有剩余,则添加两倍数量的右括号
return res
1542

tips状态压缩——用二进制数字表示有限个二态事物当前所处的状态。
举例说明:
假设有5盏灯,每盏灯存在亮灭两种状态,那么就可以使用5位二进制数进行表示。比如使用00000(2)表示5盏灯都是熄灭状态,使用11111(2)表示5盏灯都是工作状态。
本题:可以构成回文串的条件就是所有字符中,出现奇数次的字符数小于等于1。因为只需关心0~9这10个数字出现的次数是否为奇数。可见这是有限个字符的二态表示,因此可以使用状态压缩。用0表示当前数出现的次数为偶数,1表示当前数出现的次数为奇数。如“1234567890”,对应的二进制数值为:1111111111,其中0~9出现的次数均是奇数,用1表示;“112334455”对应的二进制数为0000000100,其中2出现的次数均是奇数,用1表示,其余为0。
算法思想

  1. 两个相同的状态表示之间所增加的字符必定都是偶数个。
  2. 两个只错1位的状态表示之间所增加的字符必定只有1个是奇数个。

举例说明

  1. 原始字符串“1”,对应的状态表示:“0000000010”。所增加字符均为偶数个(0022)。新的字符串“10022”,对应的状态表示:“0000000010”。
  2. 原始字符串“1”,对应的状态表示:“0000000010”。所增加字符存在一个为奇数个(00223)。新的字符串“100223”,对应的状态表示:“0000001010”。
cur_status_ind = {0:-1}  # 初始化,便于计算s[0]。这里最好结合示例走一遍
res = 1  # 答案最少为1
status = 0  # 初始化压缩表示
for i in range(len(s)):
    status ^= 1<<(ord(s[i]) - ord('0'))
    # 若记录中存在status,则增加的必定是回文串,更新res
    if status in cur_status_ind:
        res = max(res, i - cur_status_ind[status])
    else:
        cur_status_ind[status] = i
    
    # 若记录中存在与new_status相差1位的status,则增加的必定是回文串,更新res
    for j in range(10):
        new_status = status ^ (1<<j)
        if new_status in cur_status_ind:
            res = max(res, i - cur_status_ind[new_status])
return res
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页