5194. 得到目标值的最少行动次数
class Solution:
def minMoves(self, target: int, maxDoubles: int) -> int:
ans = 0
while maxDoubles>0 and target!=1: # 优先考虑除法【减半】
if target%2==0: # 偶数方可进行除法操作
maxDoubles -= 1
target //= 2 # 目标值减半
else:
target -= 1
ans += 1
# 若不能进行除法操作了,则只能递减操作,每次 -1
ans += target-1
return ans
作者:flix
链接:https://leetcode-cn.com/problems/minimum-moves-to-reach-target-score/solution/ni-xiang-tan-xin-ji-suan-cong-target-dao-hywd/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
1405. 最长快乐字符串
注意贪心策略,是优先使用当前数量最多的字符串,而不是把当前数量最多的字符串使用2个。
class Solution:
def longestDiverseString(self, a: int, b: int, c: int) -> str:
ans = []
cnt = [[a, 'a'], [b, 'b'], [c, 'c']]
while True:
cnt.sort(key=lambda x: -x[0])
hasNext = False
for i, (c, ch) in enumerate(cnt):
if c <= 0:
break
if len(ans) >= 2 and ans[-2] == ch and ans[-1] == ch:
continue
hasNext = True
ans.append(ch)
cnt[i][0] -= 1
break
if not hasNext:
return ''.join(ans)
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/longest-happy-string/solution/zui-chang-kuai-le-zi-fu-chuan-by-leetcod-5nde/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
6005. 使数组变成交替数组的最少操作数
20220213周赛的t2,我自己做的126/127个case。有一个case没通过。
思路:用哈希表存储,奇数位相等,偶数位相等,且奇数位和偶数位不等。
错误的地方:没有想好当两个key相等的时候要如何处理。
class Solution(object):
def minimumOperations(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
#奇数位相等,偶数位相等,且奇数位和偶数位不等
maps1={}
count1=0
counta=0
key1=0
maps2={}
count2=0
countb=0
key2=0
for i in range(len(nums)):
if i%2==0:
if nums[i] in maps1:
maps1[nums[i]]+=1
else:
maps1[nums[i]]=1
if maps1[nums[i]]>count1:
count1=maps1[nums[i]]
key1=nums[i]
counta+=1
else:
if nums[i] in maps2:
maps2[nums[i]]+=1
else:
maps2[nums[i]]=1
if maps2[nums[i]]>count2:
count2=maps2[nums[i]]
key2=nums[i]
countb+=1
#奇数位和偶数位的count最大值
# maps1 = sorted(maps1.items(), key=lambda x: x[1],,reverse = True)
# maps2 = sorted(maps2.items(), key=lambda x: x[1],,reverse = True)
if key1==key2 and len(maps1)-len(maps2)<=1 and len(maps1)<=2::
return min(counta-count1+countb,count1)
return counta-count1+countb-count2
哈希表计数+贪心
class Solution:
def minimumOperations(self, nums: List[int]) -> int:
n = len(nums)
if n == 1:
return 0
cnt0 = Counter(nums[::2]) # 从0开始,间隔为2
cnt1 = Counter(nums[1::2]) # 从1开始,间隔为2
cnt0 = sorted(cnt0.items(), key=lambda x: -x[1]) # 按照出现次数倒序排列
cnt1 = sorted(cnt1.items(), key=lambda x: -x[1])
if cnt0[0][0] != cnt1[0][0]: # 两个数组中,出现次数最多的元素不同
return n-cnt0[0][1]-cnt1[0][1]
else: # 两个数组中,出现次数最多的元素相同
cost0 = n - cnt0[0][1] - (0 if len(cnt1)==1 else cnt1[1][1]) # 保留第一个数组中出现次数最多的元素,并考虑保留第二个数组中出现次数第二多的元素
cost1 = n - cnt1[0][1] - (0 if len(cnt0)==1 else cnt0[1][1]) # 保留第二个数组中出现次数最多的元素,并考虑保留第一个数组中出现次数第二多的元素
return min(cost0, cost1) # 两种情况取最小值
作者:flix
链接:https://leetcode-cn.com/problems/minimum-operations-to-make-the-array-alternating/solution/tan-xin-pai-xu-qi-ou-tong-ji-bing-fen-le-vch8/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
5998. 拆分成最多数目的偶整数之和
class Solution:
def maximumEvenSplit(self, finalSum: int) -> List[int]:
if finalSum % 2 != 0:
return []
ans = []
now = 2
while finalSum > 0:
if finalSum < now:
ans[-1] += finalSum
finalSum = 0
else:
ans.append(now)
finalSum -= now
now += 2
return ans
作者:吴自华
链接:https://leetcode-cn.com/circle/discuss/dinFl3/view/qn5Ww5/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
420. 强密码检验器
字符串贪心
class Solution {
int curLen = 0;
int hasLower = 0, hasUpper = 0, hasNumber = 0;
List<Integer> continuousNum = null;
public int strongPasswordChecker(String password) {
//init
hasLower = 0; hasUpper = 0; hasNumber = 0;
continuousNum = new ArrayList<>();
curLen = password.length();
char[] cs = password.toCharArray();
for(char c : cs) {
if(Character.isLowerCase(c)) hasLower=1;
if(Character.isUpperCase(c)) hasUpper=1;
if(Character.isDigit(c)) hasNumber=1;
}
int miss = 3 - hasLower - hasUpper - hasNumber;
for(int i=0; i<curLen;) {
int j=i;
while(j<curLen && cs[j]==cs[i]) j++;
if(j-i>=3) continuousNum.add(j-i);
i = j;
}
//classified discussion
if(curLen<6) { //insertion only
return Math.max(miss, 6-curLen);
}else if(curLen>=6 && curLen<=20) { //substitute only
int res = 0;
for(int conti : continuousNum) res+= conti/3;
return Math.max(res, miss);
}else { //delete + substitute
int[] modCnt = new int[3];
for(int conti: continuousNum) modCnt[conti%3]++;
int delete = curLen-20;
int substitute = 0;
for(int conti : continuousNum) substitute += conti/3;
//some delete can save substitute
int save = 0, delRemain = delete;
for(int mod=0; mod<2; mod++) {
int ratio = mod+1;
while(modCnt[mod]>0 && delRemain>=ratio) {
modCnt[mod]--;
save++;
delRemain -= ratio;
}
}
save += delRemain/3;
int substituteFinal = substitute - save;
int res = delete + Math.max(miss, substituteFinal);
return res;
}
}
}
作者:dian-dian-13
链接:https://leetcode-cn.com/problems/strong-password-checker/solution/-by-dian-dian-13-3f55/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
553. 最优除法
数学类贪心 ![](https://i-blog.csdnimg.cn/blog_migrate/aff16d737c105e8803b2bc16c4b5b92f.png)
class Solution(object):
def optimalDivision(self, nums):
"""
:type nums: List[int]
:rtype: str
"""
#贪心,希望能够得到一顿除之后的最大结果,那么肯定是希望除的数越小越好。
res=""
if len(nums)==1:
return str(nums[0])
if len(nums)==2:
return str(nums[0])+str("/")+str(nums[1])
for i in range(len(nums)):
if i==0:
res+=str(nums[i])+str("/")+str("(")
elif i==len(nums)-1:
res+=str(nums[i])+str(")")
else:
res+=str(nums[i])+str("/")
return res
分冶可求最大值
class Solution(object):
def optimalDivision(self, nums):
"""
:type nums: List[int]
:rtype: str
"""
def dfs(start,end):
if start==end:
return [nums[start]]
res=[]
for i in range(start,end):
left=dfs(start,i)
right=dfs(i+1,end)
for l in left:
for r in right:
ans=l/r
res.append(ans)
print(start,end,res)
return res
dfs(0,len(nums)-1)
564. 寻找最近的回文数
5227. K 次操作后最大化顶端元素
周赛题,分类讨论情况没考虑全,贴一下我当时做的代码
class Solution(object):
def maximumTop(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: int
"""
k=k%len(nums)
import bisect
del_list=[]
while k>1:
#在第一个元素之前一直删除,del_list为升序列表
if len(nums)>=1:
# del_list.append(nums[0])
bisect.insort(del_list, nums[0])
nums.pop(0)
k=k-1
else:
#删到列表空了,还没到最后一个元素,从最小值插入
nums.append(del_list[0])
del_list.pop(0)
k=k-1
#判断nums第2个元素,和del_list最大元素
if len(nums)>1 and len(del_list)>=1:
if nums[1]>del_list[-1]:
return nums[1]
else:
if len(del_list)>=1:
return del_list[-1]
return -1
if len(nums)==1 and len(del_list)>=1:
return del_list[-1]
if len(del_list)>=1:
return del_list[-1]
if len(nums)>1:
return nums[1]
else:
return -1
class Solution(object):
def maximumTop(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: int
"""
#分类讨论,k==len(nums),k>len(nums),k<len(nums)
#只有一个数,且操作奇数次时,最后必空
if len(nums)==1 and k%2==1:
return -1
if k==1:
return nums[1]
if k==0:
return nums[0]
#k==len(nums),先取k-1个数,然后返回一个最大的(最后一次)
if len(nums)==k:
return max(nums[:k-1])
#k<len(nums),先取k-1个数.然后比较剩下的第二个数和取出来的数
if k<len(nums):
a1=max(nums[:k-1])
a2=nums[k]
return max(a1,a2)
#k>len(nums)
if k>len(nums):
return max(nums)
计数类型脑筋急转弯
贪心变形
2038. 如果相邻两个颜色均相同则删除当前颜色
class Solution {
public boolean winnerOfGame(String colors) {
char[] cs = colors.toCharArray();
int n = cs.length;
int a = 0, b = 0;
for (int i = 1; i < n - 1; i++) {
if (cs[i] == 'A' && cs[i - 1] == 'A' && cs[i + 1] == 'A') a++;
if (cs[i] == 'B' && cs[i - 1] == 'B' && cs[i + 1] == 'B') b++;
}
return a > b;
}
}
作者:AC_OIer
链接:https://leetcode-cn.com/problems/remove-colored-pieces-if-both-neighbors-are-the-same-color/solution/gong-shui-san-xie-nao-jin-ji-zhuan-wan-y-a8xm/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
2211. 统计道路上的碰撞次数
分左边和右边计算
class Solution:
def countCollisions(self, directions: str) -> int:
count = 0
# 如果l的左边有R或者S
flag = False
for i in range(len(directions)):
if directions[i] != 'L' and flag == False:
flag = True
if directions[i] == 'L' and flag == True:
count += 1
# 如果R的右边有L或者S,一定会碰撞
flag = False
for i in range(len(directions) - 1, -1, -1):
if directions[i] != 'R' and flag == False:
flag = True
if directions[i] == 'R' and flag == True:
count += 1
return count
134. 加油站
上帝视角反推
class Solution(object):
def canCompleteCircuit(self, gas, cost):
"""
:type gas: List[int]
:type cost: List[int]
:rtype: int
"""
if sum(gas) < sum(cost):
return -1
fuel = 0
start = 0
for i in range(len(gas)):
#从i开到下一个加油站时,邮箱里还剩下的油
cur = gas[i] - cost[i]
fuel += cur
if fuel < 0:
#到达不了下一个加油站
start = i+1
fuel = 0
return start
6187. 完成所有交易的初始最少钱数
1665. 完成所有任务的最少初始能量
376. 摆动序列
相邻两个元素
func wiggleMaxLength(nums []int) int {
n := len(nums)
if n <=1{
return n
}
preDiff, curDiff := 0, 0
maxLength := 1
for i:=1;i<n;i++{
curDiff = nums[i] - nums[i-1]
// 只要满足正负数交替出现,则累加最大摆动子序列长度,并更新preDiff为curDiff
if (curDiff > 0 && preDiff <=0) || (curDiff < 0 && preDiff >= 0){
maxLength++
preDiff = curDiff
}
}
return maxLength
}
作者:ybzdqhl
链接:https://leetcode-cn.com/problems/wiggle-subsequence/solution/tan-xin-suan-fa-jie-jue-jian-dan-yi-dong-17v6/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution:
def wiggleMaxLength(self, nums: List[int]) -> int:
#思想和今天0327周赛t2有点像,从左到右贪心
#当count = 0的时候,找开始的时候是什么样子的。
#当count大于0的时候,根据pre_flag来判断上一次的状态,本次要和上一次的涨停相反。
count = 0
pre_index = 0
cur_index = 1
while cur_index < len(nums):
# if nums[pre_index] == nums[cur_index]:
# cur_index += 1
if count > 0:
if nums[pre_index] < nums[cur_index] and pre_flag == 1:
count += 1
pre_flag = 0
pre_index += 1
cur_index += 1
elif nums[pre_index] > nums[cur_index] and pre_flag == 0:
count += 1
pre_flag = 1
pre_index += 1
cur_index += 1
else:
pre_index += 1
cur_index += 1
else:
if nums[pre_index] < nums[cur_index]:
count += 1
pre_flag = 0
pre_index += 1
cur_index += 1
elif nums[pre_index] > nums[cur_index]:
count += 1
pre_flag = 1
pre_index += 1
cur_index += 1
else:
pre_index += 1
cur_index += 1
return count+1
135. 分发糖果
分左边和右边计算
可用“贡献”的角度,左边对最终结果的的贡献(影响),右边的贡献,取最大值
6040. 花园的最大总美丽值
超时,需要优化
class Solution(object):
def maximumBeauty(self, flowers, newFlowers, target, full, partial):
"""
:type flowers: List[int]
:type newFlowers: int
:type target: int
:type full: int
:type partial: int
:rtype: int
"""
# 贪心,能种满的就种满。剩下不能种满的,另最小值最大(爱吃香蕉的可可),最小值为x,二分找x
# flowers从大到小排序,能种满的就种满,不行,要枚举
def full_fun(count, newFlowers):
remain_flower = newFlowers
index = 0
ans = 0
while index < len(flowers0) and remain_flower > 0 and index < count:
cost_flower = target - flowers0[index]
if cost_flower > 0 and remain_flower >= cost_flower:
remain_flower -= cost_flower
elif cost_flower > 0 and remain_flower < cost_flower:
break
ans += full
index += 1
return index, ans,remain_flower
# 剩下的是不能种满的,newFlowers条件不满足,flower从index开始.二分
def check(x,remain_flower):
tmp_sum = 0
j = 0
while j < len(flowers1):
if flowers1[j] >= x:
tmp_sum += flowers1[j]
j += 1
else:
break
lens = len(flowers1) - j
tmp_sum += lens*x
if tmp_sum - sum(flowers1) <= remain_flower:
return True
return False
flowers.sort(reverse=True)
#先把完善的拿出来,并去掉
extra_ans = 0
i = 0
while i < len(flowers):
if flowers[i] >= target:
extra_ans += full
i += 1
else:
break
flowers0 = flowers[i:]
ans = extra_ans
for i in range(len(flowers0)+1):
index, cur_ans ,remain_flower = full_fun(i, newFlowers)
cur_ans += extra_ans
flowers1 = flowers0[index:]
if len(flowers1) > 0:
left = flowers1[-1]
right = min(flowers1[0] + remain_flower,target - 1)
flag = False
while left <= right:
mid = (left + right) // 2
flag = True
# 如果这个值满足,把它放大看看
if check(mid,remain_flower):
left = mid + 1
else:
right = mid - 1
# left-1就是这个最大的最小值
if flag == True:
cur_ans += (left - 1) * partial
ans = max(ans, cur_ans)
return ans
贪心+二分+前缀和
这个题非常考验二分和前缀和的基本功,调了半天才通过。
# if (pre_sum[j] - pre_sum[index+1]) + lens * x - sum(flowers0[index+1:]) <= remain_flower,这句话超时,得改成前缀和,服了
class Solution(object):
def maximumBeauty(self, flowers, newFlowers, target, full, partial):
"""
:type flowers: List[int]
:type newFlowers: int
:type target: int
:type full: int
:type partial: int
:rtype: int
"""
# 贪心,能种满的就种满。剩下不能种满的,另最小值最大(爱吃香蕉的可可),最小值为x,二分找x
# flowers从大到小排序,能种满的就种满,不行,要枚举,枚举的时候别纯暴力,下一次跟上一次有关系
def check2(x, remain_flower):
# 找flowers1中大于x的最后一个index
# j = bisect.bisect_left(flowers1, x) - 1
# print(flowers1,x,j)
left1 = index+1
right1 = len(flowers0) - 1
while left1 <= right1:
mid1 = (left1 + right1) // 2
if flowers0[mid1] >= x:
left1 = mid1 + 1
else:
right1 = mid1 - 1
j = left1
lens = len(flowers0) - j
# if (pre_sum[j] - pre_sum[index+1]) + lens * x - sum(flowers0[index+1:]) <= remain_flower:
if (pre_sum[j] - pre_sum[index + 1]) + lens * x - (pre_sum[-1] - pre_sum[index + 1]) <= remain_flower:
return True
return False
flowers.sort(reverse=True)
index = 0
while index < len(flowers):
if flowers[index] >= target:
index += 1
else:
break
flowers0 = flowers[index:]
pre_sum = [0 for _ in range(len(flowers0) + 1)]
for k in range(1, len(flowers0) + 1):
pre_sum[k] = pre_sum[k - 1] + flowers0[k - 1]
#比target大的肯定是完善的
ans0 = full*index
if index == len(flowers):
return ans0
ans = float("-inf")
#从第一位开始,把第一位填满,剩下的不填满,然后再把第二位填满
index = -1
while index < len(flowers0):
#把index位填满,要考虑都不填满的情况
cur_ans = ans0
if index>=0 :
cur_cost = target - flowers0[index]
if newFlowers >= cur_cost:
newFlowers -= cur_cost
cur_ans += full*(index+1)
if index < len(flowers0)-1:
#剩下的二分找最小值的最大值
left = flowers0[-1]
right = min(flowers0[index+1] + newFlowers, target - 1)
flag = False
while left <= right:
mid = (left + right) // 2
flag = True
# 如果这个值满足,把它放大看看
if check2(mid, newFlowers):
left = mid + 1
else:
right = mid - 1
# left-1就是这个最大的最小值
if flag == True:
cur_ans += (left - 1) * partial
index += 1
ans = max(ans, cur_ans)
if index>=0 and newFlowers < (target - flowers0[index]):
break
print(cur_ans)
return ans
968 监控二叉树
贪心+后序遍历
class Solution:
def minCameraCover(self, root: TreeNode) -> int:
# Greedy Algo:
# 从下往上安装摄像头:跳过leaves这样安装数量最少,局部最优 -> 全局最优
# 先给leaves的父节点安装,然后每隔两层节点安装一个摄像头,直到Head
# 0: 该节点未覆盖
# 1: 该节点有摄像头
# 2: 该节点有覆盖
result = 0
# 从下往上遍历:后序(左右中)
def traversal(curr: TreeNode) -> int:
nonlocal result
if not curr: return 2
left = traversal(curr.left)
right = traversal(curr.right)
# Case 1:
# 左右节点都有覆盖
if left == 2 and right == 2:
return 0
# Case 2:
# left == 0 && right == 0 左右节点无覆盖
# left == 1 && right == 0 左节点有摄像头,右节点无覆盖
# left == 0 && right == 1 左节点有无覆盖,右节点摄像头
# left == 0 && right == 2 左节点无覆盖,右节点覆盖
# left == 2 && right == 0 左节点覆盖,右节点无覆盖
elif left == 0 or right == 0:
result += 1
return 1
# Case 3:
# left == 1 && right == 2 左节点有摄像头,右节点有覆盖
# left == 2 && right == 1 左节点有覆盖,右节点有摄像头
# left == 1 && right == 1 左右节点都有摄像头
elif left == 1 or right == 1:
return 2
# 其他情况前段代码均已覆盖
if traversal(root) == 0:
result += 1
return result
871. 最低加油次数
用dfs超时。
class Solution(object):
def minRefuelStops(self, target, startFuel, stations):
"""
:type target: int
:type startFuel: int
:type stations: List[List[int]]
:rtype: int
"""
if not stations:
if startFuel >= target:
return 0
return -1
#开往下一个加油站时,如果到达不了,就从以前的加油站里选油量最大的加油
#子问题是:到达当前加油站,最少的加油次数
now_fuel = startFuel
heap = []
res = 0
for i in range(len(stations)):
#从上一个加油站到达当前加油站需要消耗的fuel
cur_state = stations[i][0]
if i == 0:
cost = cur_state
else:
cost = cur_state - stations[i-1][0]
#到达不了,开始加油
now_fuel -= cost
while now_fuel < 0:
if heap:
add_fuel = -heapq.heappop(heap)
now_fuel += add_fuel
res += 1
else:
return -1
heapq.heappush(heap,-stations[i][1])
#从最后一个加油站到达target
cost = target - stations[-1][0]
#到达不了,开始加油
now_fuel -= cost
while now_fuel < 0:
if heap:
add_fuel = -heapq.heappop(heap)
now_fuel += add_fuel
res += 1
else:
return -1
return res
435. 无重叠区间
无重叠区间,452. 用最少数量的箭引爆气球。和会议室2(上下车问题)的区别是:
会议室2是求的区间最大重叠值,射气球不是求的区间最大重叠值,是求的最大不重叠的区间数,这两个是不一样的。
class Solution(object):
def eraseOverlapIntervals(self, intervals):
"""
:type intervals: List[List[int]]
:rtype: int
"""
#总共的区间数,减去不重叠的区间数
intervals.sort(key = lambda x:x[1])
end = intervals[0][1]
count = 1
for i in range(1,len(intervals)):
if end <= intervals[i][0]:
count += 1
end = intervals[i][1]
return len(intervals) - count
6144. 将数组排序的最少替换次数
贪心+数学
为什么最小值最大是 11 / 份数?因为要尽可能的均分,才会最小值最大。
class Solution(object):
def minimumReplacement(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
#从后往前遍历
#如果cur能整除pre,就整除
#如果不能整除,分成的份数是 cur // pre + 1
#从后往前
count = 0
i = len(nums) - 2
cur = nums[-1]
while i >= 0:
pre = nums[i]
if pre > cur:
if pre % cur == 0:
#pre不变(前面挨着的最小值不变)
count += pre // cur - 1
pre = cur
else:
fenshu = pre // cur + 1
count += pre // cur
pre = pre // fenshu
i -= 1
cur = pre
return count
2350. 不可能得到的最短骰子序列
2337. 移动片段得到字符串
2332. 坐上公交的最晚时间
2333. 最小差值平方和
169 多数元素
摩尔投票法