Leetcode周赛_201学习笔记(滴滴)

学习来源:

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

1544 整理字符串

题意理解:给定字符串,若存在连续的2个字符,后者为前者的大写,或者后者为前者的小写,则删除这两个字符。重复此操作直至字符串不能再修改。
算法思想:按照题意写朴素算法即可。

res = []
for i in s:
    if not res:
        res.append(i)
    elif abs(ord(res[-1])-ord(i))==32:
        res.pop(-1)
    else:
        res.append(i)
res_s = ''
for i in res:
    res_s += i
return res_s
1545 找出第N个二进制字符串中的第K位

题意理解:按照题目要求构建S字符串,返回最终结果中的第K位。
算法思想

  1. 朴素算法,暴力求解。这里要留意题目所给信息,n∈[1, 20],尽量避免超时。
# 朴素算法,通常存在超时的可能
s = ['0']
# 构建所有S
for i in range(1,20):
    tmp = s[i-1] + '1'  # 增加字符1
    re_list = list(s[i-1])
    reverse_s = ''
    for j in range(len(re_list)-1,-1,-1):  # 倒序遍历,补充后半部分
        if re_list[j] == '1':
            reverse_s += '0'
        else:
            reverse_s += '1'
    tmp += reverse_s
    s.append(tmp)
return s[n-1][k-1]  # 直接Hash返回结果
  1. 结合数学分析的方法。索引K无外乎3种情况:恰好为中点、中点左侧和中点右侧。根据不同情况的特点、从SnS2更新索引即可。
# 结合数学分析的算法
# 首先计算出所有的字符串长度
len_list = [1]
for i in range(20):
    len_cur = len_list[-1]
    len_list.append(len_cur * 2 + 1)

# 对索引进行更新
ind = k
change = -1  # 记录转换次数
res = 0
# 这里的更新不能包含S1,因为S1是最初的字符串,中间字符不是‘1’
for i in range(n-1,0,-1):
	# 计算当前字符串中间字符的索引
    mid = (len_list[i]+1)//2
    # 当前索引等于中间字符索引,则根据添加规则,返回‘1’
    if ind == mid:
        res = 1
        break
    '''
    当前索引大于中间字符索引,则根据添加规则,更新索引为 mid * 2 - ind,同时更新转换次数
    解释:因为当前索引大于中间字符索引,且字符串关于中间字符对称(仅考虑长度)。
    	 首先计算当前索引至中间字符的距离:l = ind - mid
    	 随后,利用对称性可知,索引应当更新为中间字符减去l:new_ind = mid - l = 2 * mid - ind
    '''
    elif ind > mid:
        new_ind = mid * 2 - ind
        ind = new_ind
        change *= -1
    else:
    	# 若当前索引小于中间字符索引,则无需更新
    	continue

# 若change为1,说明变换了偶数次,反之变换了奇数次,需要将res变换
if res == 0:
    if change == -1:
        return "0"
    else:
        return "1"
else:
    if change == -1:
        return "1"
    else:
        return "0"
1546 和为目标值的最大数目不重叠非空子数组数目

题意理解:给定数组nums,返回和为target的子数组的最大数目,要求子数组之间不能重叠。
算法分析:前缀和 + 贪心。其中贪心的思想体现在:从前向后的遍历时,只要找到符合要求的子数组,就进行计数。

cur_sum = 0  # 当前计数之和
prefix = set([0])  # 记录前缀和
res = 0
for i in nums:
    cur_sum += i
    if cur_sum - target in prefix:
    '''
    cur_sum - (cur_sum - target) = target。
    显然,(cur_sum - target, cur_sum]之间的元素之和为target。
    即找到一符合要求的子数组,更新前缀和set。
    '''
        prefix = set([0])
        cur_sum = 0
        res += 1
    else:
        prefix.add(cur_sum)
return res

560 和为K的子数组,该题可以辅助理解前缀和的计算过程。

1547 切棍子的最小成本

题意理解:长度为l的木棍,切开的成本为l。现给定切割位置,求使得总成本最小的切割顺序。
算法分析:区间dp,dp[start][end]表示端点为startend的木棍进行切割时的最小成本。

cuts.extend([0,n])
cuts.sort()
lens = len(cuts)
dp = [[0] * lens for _ in range(lens)]
MAX_NUM = float("inf")
for end in range(2,lens):  # end小于2时,木棍不存在或者切割点不存在,无意义
    for start in range(end-1,-1,-1):
        if end - start == 1:  # 该段木棍没有需要切割的地方
            continue
        if end - start == 2:  # 该段木棍只有一个需要切割的地方
            dp[start][end] = cuts[end] - cuts[start]
        else:  # 该段木棍中间存在多个需要切割的地方
            dp[start][end] = MAX_NUM
            for i in range(start+1,end):
                dp[start][end] = min(dp[start][end], dp[start][i] + dp[i][end] + cuts[end] - cuts[start])
return dp[0][lens-1]

你可能感兴趣的:(leetcode,python)