暑期练习

0705

494. 目标和

首先考虑了使用dfs但是结果超时

class Solution:
    def findTargetSumWays(self, nums: List[int], target: int) -> int:
        def dfs(nums,target,index,n):
            if n==index: 
                if target==0:
                    return 1
                else :
                    return 0
            return dfs(nums,target-nums[index],index+1,n)+dfs(nums,target+nums[index],index+1,n)
        return dfs(nums,target,0,len(nums))

接着使用dp得到结果
遍历[-1000,1000]的所有可能性
j + 1000是为了变量的映射
dp[i-1][j + 1000]可以直接跳到dp[i][j + nums[i] + 1000]和dp[i][j - nums[i] + 1000],理由是i-1 \(\rightarrow\) i只需要\(\pm\) nums[i]+1000,原因是dp[i][j]是i个数组成数字j的方案数。

class Solution:
    def findTargetSumWays(self, nums: List[int], target: int) -> int:
        n = len(nums)
        dp = [[0] * 2001 for _ in range(n)]
        dp[0][nums[0] + 1000] += 1
        dp[0][-nums[0] + 1000] += 1
        for i in range(1, n):
            for j in range(-1000, 1001):
                if dp[i-1][j + 1000] > 0:
                    dp[i][j + nums[i] + 1000] += dp[i-1][j + 1000]
                    dp[i][j - nums[i] + 1000] += dp[i-1][j + 1000]
        return dp[n-1][target + 1000]

3115. 质数的最大距离

"""
简单的判断,双指针左右同时搜索,遇到第一个质数就停下,如果两个指针都停下就结束返回结果
需要注意的重点是continue不要忘记,遇到了质数之后指针不需要继续向前,以及while f or r:,应该是两个指针都查找到才停止,只要有一个没有找到就应该继续,所以需要使用or而不是and。
"""
class Solution:
    def maximumPrimeDifference(self, nums: List[int]) -> int:
        def is_prime(num):
            if num <= 1:
                return False
            for i in range(2, int(num**0.5) + 1):
                if num % i == 0:
                    return False
            return True
        n=len(nums)
        left=0
        right=n-1
        f,r=True,True
        while f or r:
            if f:
                if is_prime(nums[left]):
                    f=False
                    continue
                left+=1
            if r:
                if is_prime(nums[right]):
                    r=False
                    continue
                right-=1
        return right-left

//Java
class Solution {
    public int maximumPrimeDifference(int[] nums) {
        int n=nums.length;
        int left=0;
        int right=n-1;
        boolean f = true; 
        boolean r = true;
    while (f || r) {
        if (f) {
            if (isPrime(nums[left])) {
                f = false;
                continue;
            }
            left++;
        }
        if (r) {
            if (isPrime(nums[right])) {
                r = false;
                continue;
            }
            right--;
        }
    }
    
    return right - left;
}

private boolean isPrime(int num) {
    if (num <= 1) {
        return false;
    }
    for (int i = 2; i <= Math.sqrt(num); i++) {
        if (num % i == 0) {
            return false;
        }
    }
    return true;
}
}

3099. 哈沙德数

#非常基础
class Solution {
    public int sumOfTheDigitsOfHarshadNumber(int x) {
        int sum=0;
        int temp=x;
        while (temp>0){
            sum += temp % 10;
            temp /= 10;
        }
        if (x%sum==0){
            return sum;
        }
        else{
            return -1;
        }
    }
}

3033. 修改矩阵

#基础题
class Solution:
    def modifiedMatrix(self, matrix: List[List[int]]) -> List[List[int]]:
        m=len(matrix)
        n=len(matrix[0])
        record=[]
        ma=[0]*n
        for i in range(n):
            for j in range(m):
                if matrix[j][i]==-1:
                    record.append([j,i])
                ma[i]=max(ma[i],matrix[j][i])
        for j,i in record:
            matrix[j][i]=ma[i]
        return matrix

0706

3101. 交替子数组计数

"""
本题重点是理解,dp[i]的状态,我这里假设的是以nums[i]为结尾的子数组为交替子数组的数量,所以结尾需要sum(dp)
装填转移方程为1. 
$$
dp[i]=dp[i-1]+1 if nums[i] != nums[i-1]
dp[i]=1 if nums[i] = nums[i-1]
$$
举[1,2,2,1]作为例子
i=0时显然dp[0]=1,i=1的时候dp[1]=1+1=2{[2],[1,2]两种[1]不算在内,因为假设的是以nums[i]为结尾的子数组为交替子数组的数量)}
dp[2]=1,dp[3]=2
return 1+2+2+1=6
"""
class Solution:
    def countAlternatingSubarrays(self, nums: List[int]) -> int:
        n = len(nums)
        if n == 1:
            return 1
        dp= [1] * n
        dp[1]= 2 if nums[0] != nums[1] else 1
        for i in range(2,n):
            if nums[i] != nums[i-1]:
                dp[i] = dp[i-1]+1
            else:
                dp[i] = 1
        return sum(dp)

接下来是用时和内存的改进,使用滚动数组,因为我们注意到状态只和前一个状态有关也就是dp[i]只会和dp[i-1]有关,因此我们只需要一个参数last记录前一状态即可

class Solution:
    def countAlternatingSubarrays(self, nums: List[int]) -> int:
        n = len(nums)
        res=1
        if n == 1:
            return res
        last=2 if nums[0]!=nums[1] else 1
        res+=last
        for i in range(2,n):
            if nums[i] != nums[i-1]:
                last = last+1
            else:
                last = 1
            res+=last
        return res

0707

1958. 检查操作是否合法

#纯纯折磨人,枚举
class Solution:
    def checkMove(self, board: List[List[str]], rMove: int, cMove: int, color: str) -> bool:
        # 判断每个方向是否存在以操作位置为起点的好线段
        def check(dx: int, dy: int) -> bool:
            x, y = rMove + dx, cMove + dy
            step = 1   # 当前遍历到的节点序号
            while 0 <= x < 8 and 0 <= y < 8:
                if step == 1:
                    # 第一个点必须为相反颜色
                    if board[x][y] == "." or board[x][y] == color:
                        return False
                else:
                    # 好线段中不应存在空格子
                    if board[x][y] == ".":
                        return False
                    # 遍历到好线段的终点,返回 true
                    if board[x][y] == color:
                        return True
                step += 1
                x += dx
                y += dy
            # 不存在符合要求的好线段
            return False
        
        # 从 x 轴正方向开始逆时针枚举 8 个方向
        dx = [1, 1, 0, -1, -1, -1, 0, 1]   # 行改变量
        dy = [0, 1, 1, 1, 0, -1, -1, -1]   # 列改变量
        for k in range(8):
            if check(dx[k], dy[k]):
                return True
        return False

100339. 找出加密后的字符串

class Solution:
    def getEncryptedString(self, s: str, k: int) -> str:
        n = len(s)
        ret = ""
        for i in range(n):
            tmp = (i+k)%n
            ret += s[tmp]
        return ret

100328. 生成不含相邻零的二进制字符串

class Solution:
    def validStrings(self, n: int) -> List[str]:
        if n == 1:
            return ["0", "1"]

        queue = deque([["0", "0"]])
        queue.append(["1", "1"])
        res = []

        while queue:
            q = queue.popleft()
            if len(q[1]) == n:
                res.append(q[1])
            else:
                if q[0] == "0":
                    queue.append(["1", q[1] + "1"])
                if q[0] == "1":
                    queue.append(["0", q[1] + "0"])
                    queue.append(["1", q[1] + "1"])

        return res

100359. 统计 X 和 Y 频数相等的子矩阵数量

class Solution:
"""
使用prefix_x_count[i][j]记录[0][0] &\rightarrow& [i][j]位置的前缀和x的总数,使用prefix[i][j]记录 [0][0] &\rightarrow& [i][j]位置的 x - y的差值
"""
    def numberOfSubmatrices(self, grid: List[List[str]]) -> int:
        m, n = len(grid), len(grid[0])
        prefix = [[0] * n for _ in range(m)]
        prefix_x_count = [[0] * n for _ in range(m)]
        res = 0
        for i in range(m):
            for j in range(n):
                x = 1 if grid[i][j] == 'X' else 0
                if i > 0:
                    x += prefix_x_count[i - 1][j]
                if j > 0:
                    x += prefix_x_count[i][j - 1]
                if i > 0 and j > 0:
                    x -= prefix_x_count[i - 1][j - 1]
                prefix_x_count[i][j] = x
        for i in range(m):
            for j in range(n):
                x = 1 if grid[i][j] == 'X' else 0
                y = 1 if grid[i][j] == 'Y' else 0
                if i > 0:
                    x += prefix[i - 1][j]
                if j > 0:
                    x += prefix[i][j - 1]
                if i>0 and j>0:
                    x -= prefix[i - 1][j - 1]
                prefix[i][j] = x - y
                if prefix[i][j] == 0 and prefix_x_count[i][j] >0:
                    res += 1
        return res

0708

724. 寻找数组的中心下标

#基础题
class Solution:
    def pivotIndex(self, nums: List[int]) -> int:
        left=0
        Sum=sum(nums)
        n=len(nums)
        for i in range(n):
            right=Sum-left-nums[i]
            if left==right:
                return i
            else:
                left+=nums[i]
        return -1
class Solution {
    public int pivotIndex(int[] nums) {
        int left=0;
        int Sum = Arrays.stream(nums).sum();
        int n=nums.length;
        int right;
        for (int i=0;i<n;i++){
            right=Sum-left-nums[i];
            if(right==left){
                return i;
            }
            else{
                left+=nums[i];
            }
        }
        return -1;
    }
}

0709

2785. 将字符串中的元音字母排序

class Solution:
    def sortVowels(self, s: str) -> str:
        vowels = 'aeiouAEIOU'
        # 提取元音字母并排序
        vowel_list = sorted([char for char in s if char in vowels])
        
        # 结果字符串初始化为列表形式
        result = list(s)
        
        # 用于跟踪元音字母的插入位置
        vowel_index = 0
        
        # 遍历字符串,将元音字母按排序后的顺序插入到对应位置
        for i in range(len(s)):
            if s[i] in vowels:
                result[i] = vowel_list[vowel_index]
                vowel_index += 1
        
        # 将列表转换回字符串
        return ''.join(result)

2833. 距离原点最远的点

# 等级2
class Solution:
    def furthestDistanceFromOrigin(self,moves: str) -> int:
        count=Counter(moves)
        return count["_"]+abs(count["R"] - count["L"])        

0710

2970. 统计移除递增子数组的数目 I

class Solution:
    def incremovableSubarrayCount(self, nums: List[int]) -> int:
        n = len(nums)
        return sum([self.isIncreasing(nums[:i] + nums[j+1:]) for i in range(n) for j in range(i, n)])
    
    def isIncreasing(self, nums):
        if len(nums) == 0:
            return True
        return all(nums[i] < nums[i + 1] for i in range(len(nums) - 1))

0711

2139. 得到目标值的最少行动次数

# 超出内存限制
class Solution:
    def minMoves(self, target: int, maxDoubles: int) -> int:
        queue = deque([[1, 0, 0]])
        res = 10 ** 9
        while queue:
            num, cnt, d = queue.popleft()
            if num>target:
                continue
            if num == target:
                res = min(res, cnt)
                continue
            if d < maxDoubles:
                queue.append([num * 2, cnt + 1, d + 1])
            queue.append([num + 1, cnt + 1, d])
        return res
"""
这道题目需要用到逆向思维+贪心算法
因此如果当前整数为偶数,并且还有剩余的折半操作次数,我们就执行折半操作,否则执行递减操作。
"""
class Solution:
    def minMoves(self, target: int, maxDoubles: int) -> int:
        ans = 0
        while maxDoubles and target != 1:
            ans += 1
            if target % 2 == 1:
                target -= 1
            else:
                maxDoubles -= 1
                target //= 2
        ans += (target - 1)
        return ans

0712

2974. 最小数字游戏

# 基础题
class Solution:
    def numberGame(self, nums: List[int]) -> List[int]:
        nums.sort()
        n=len(nums)
        for i in range(1, n, 2):
            nums[i], nums[i-1] = nums[i-1], nums[i]
        return nums

0713

3011. 判断一个数组是否可以变为有序

class Solution:
    def canSortArray(self, nums: List[int]) -> bool:
        n = len(nums)
        i = 0
        while i < n:
            start = i
            ones = nums[i].bit_count()
            i += 1
            while i < n and nums[i].bit_count() == ones:
                i += 1
            nums[start:i] = sorted(nums[start:i])
        return all(x <= y for x, y in pairwise(nums))

0714

807. 保持城市天际线

class Solution:
    def maxIncreaseKeepingSkyline(self, grid: List[List[int]]) -> int:
        R=list(map(max,grid))
        C=list(map(max,zip(*grid)))
        n=len(R)
        res=0
        for i in range(n):
            for j in range(n):
                res+=(min(C[j],R[i])-grid[i][j])
        return res
//Java
class Solution {
    public int maxIncreaseKeepingSkyline(int[][] grid) {
        int n=grid.length;
        int [] R=new int[n];
        int [] C=new int[n];
        int res=0;
        for (int i=0;i<n;i++){
            for (int j=0;j<n;j++){
                R[i]=Math.max(R[i],grid[i][j]);
                C[j]=Math.max(C[j],grid[i][j]);

            }
        }
        for (int i=0;i<n;i++){
            for (int j=0;j<n;j++){
                res+=(Math.min(R[i],C[j])-grid[i][j]);
            }
        }
        return res;
    }
}

0715

3216. 交换后字典序最小的字符串

class Solution:
    def getSmallestString(self, s: str) -> str:
        n=len(s)
        ss=list(s)
        for i in range(n-1):
            if (int(ss[i])%2) == (int(ss[i+1])%2) and (int(ss[i]) >  int(ss[i+1])):
                ss[i],ss[i+1]=ss[i+1],ss[i]
                return "".join(ss)
        return s
//Java
class Solution {
    public String getSmallestString(String s) {
        char [] t=s.toCharArray();
        char temp=0;
        for (int i=0;i<t.length-1;i++){
            if (t[i]>t[i+1] && t[i+1]%2==t[i]%2){
                temp=t[i];
                t[i]=t[i+1];
                t[i+1]=temp;
                break;
            }
        }
        return new String(t);
    }
}

3217. 从链表中移除在数组中存在的节点

"""
应该重点注意
if cur.next.val in st:
  cur.next = cur.next.next  # 删除
else:
  cur = cur.next  # 向后移动
而不是
if cur.next.val in st:
  cur.next = cur.next.next  # 删除
cur = cur.next  # 向后移动cur.next.next就是安全的因为我们直接跳到了cur -> cur.next.next的位置然后使用cur.next导致cur.next.next从始至终都被跳过了
而且如果cur.next.next为NULL还会发生"Nonetype".next/val的错误。
这是因为如果是下者我们就以为
"""
class Solution:
    def modifiedList(self, nums: List[int], head: Optional[ListNode]) -> Optional[ListNode]:
        st = set(nums)
        cur = dummy = ListNode(next=head)
        while cur.next:
            if cur.next.val in st:
                cur.next = cur.next.next  # 删除
            else:
                cur = cur.next  # 向后移动
        return dummy.next

0716

2956. 找到两个数组中的公共元素

class Solution:
    def findIntersectionValues(self, nums1: List[int], nums2: List[int]) -> List[int]:
        res=[0,0]
        n=len(nums1)
        m=len(nums2)
        for i in range(n):
            if nums1[i] in nums2:
                res[0]+=1
        for j in range(m):
            if nums2[j] in nums1:
                res[1]+=1
        return res
//Java
class Solution {
    public int[] findIntersectionValues(int[] nums1, int[] nums2) {
        int[] res = new int[2];
        for (int x1 : nums1) {
            for (int x2 : nums2) {
                if (x1 == x2) {
                    res[0]++;
                    break;
                }
            }
        }
        for (int x2 : nums2) {
            for (int x1 : nums1) {
                if (x2 == x1) {
                    res[1]++;
                    break;
                }
            }
        }
        return res;
    }
}

0719

3096. 得到更多分数的最少关卡数目

"""
本题的重点在于range(n-1)因为每个人至少都要参加一场比赛
"""
class Solution:
    def minimumLevels(self, possible: List[int]) -> int:
        total=sum(possible)-(len(possible)-sum(possible))
        n=len(possible)
        last=0
        cur=0
        for i in range(n-1):
            if possible[i]==1:
                cur+=1
            else:
                cur-=1
            if cur>total/2:
                return i+1
        return -1
//Java的需要注意的点是float total 而不是int total
class Solution {
    public int minimumLevels(int[] possible) {
        float total=0;
        int n=possible.length;
        int cur=0;
        for (int i=0;i<n;i++){
            if (possible[i]==1){
                total+=1;
            }
            else{total-=1;}
        }
        for (int i=0;i<n-1;i++){
            if (possible[i]==1){
                cur+=1;
            }
            else{cur-=1;}
            if (cur>total/2){
                return i+1;
            }
        }
        return -1;
    }
}

0721

1186. 删除一次得到子数组最大和

"""
官网题解
dp1表示的是dp[i][1]是以arr[i]为结尾删除一次的最大子数组和
dp0表示的是dp[i][0]是以arr[i]为结尾删除零次的最大子数组和
因此dp[i][1]=max(dp[i-1][0],dp[i-1][1]+arr[i])前者指的是从dp[i-1][0]删除arr[i]直接跳到dp[i][1],后者因为[0,i-1]已经删除过一次,所以直接加上arr[i]
"""
class Solution:
    def maximumSum(self, arr: List[int]) -> bool:
        dp0, dp1, res = arr[0], 0, arr[0]
        for i in range(1, len(arr)):
            dp1 = max(dp0, dp1 + arr[i])
            dp0 = max(dp0, 0) + arr[i]
            res = max(res, max(dp0, dp1))
        return res

0722

2101. 引爆最多的炸弹

"""
错误分析
1. 引爆炸弹是单向的,我却单纯的以为是双向的,简要例子,2,3都可以引爆1但是不能说成是1引爆了2,3不答案已经改变了
2. 不需要set去记录,这个是多联通的,例子:1,2,3,4 中 4可以引爆1,3也可以啊如果使用全局visited那么1已经在开始就被我手动引爆了,如果引爆不是单向而是双向的话需要全局visited但是这里不需要因为如果是全局visited那么就是一个求联通块的问题,但是在这里只是单向联通,4->1,3->1 4和3可以是无关的因为不能通过1去引爆他们。
"""
class Solution:
    def maximumDetonation(self, bombs: List[List[int]]) -> int:
        n=len(bombs)
        G=[[0]*n for _ in range(n)]
        for i in range(n-1):
            for j in range(i+1,n):
                if (bombs[i][0]-bombs[j][0])**2+(bombs[i][1]-bombs[j][1])**2 <= (max(bombs[i][2],bombs[j][2]))**2:
                    G[i][j]=1
                    G[j][i]=1
        visited=set()
        def dfs(i):
            for j in range(n):
                if G[i][j]==1 and j not in visited:
                    visited.add(j)
                    dfs(j)
        res=0
        for i in range(n):
            if i in visited:
                continue
            else:
                last=len(visited)
                visited.add(i)
                dfs(i)
                res=max(res,len(visited)-last)
        return res
class Solution:
    def maximumDetonation(self, bombs: List[List[int]]) -> int:
        n=len(bombs)
        G=[[0]*n for _ in range(n)]
        for i in range(n):
            for j in range(n):
                if i!=j and (bombs[i][0]-bombs[j][0])**2+(bombs[i][1]-bombs[j][1])**2 <= (bombs[i][2])**2:
                    G[i][j]=1
        def dfs(i):
            for j in range(n):
                if G[i][j]==1 and j not in visited:
                    visited.add(j)
                    dfs(j)
        res=0
        for i in range(n):
            visited=set()
            dfs(i)
            visited.add(i)
            res=max(res,len(visited))
        return res
#使用邻接表
def maximumDetonation(self, bombs: List[List[int]]) -> int:
        n=len(bombs)
        G=defaultdict(list)
        for i in range(n):
            for j in range(n):
                if i!=j and (bombs[i][0]-bombs[j][0])**2+(bombs[i][1]-bombs[j][1])**2 <= (bombs[i][2])**2:
                    G[i].append(j)
        def dfs(i):
            for j in G[i]:
                if j not in visited:
                    visited.add(j)
                    dfs(j)
        res=0
        for i in range(n):
            visited=set()
            dfs(i)
            visited.add(i)
            res=max(res,len(visited))
        return res
# 使用enumerate会快一点点
class Solution:
    def maximumDetonation(self, bombs: List[List[int]]) -> int:
        n=len(bombs)
        G=defaultdict(list)
        for i, (x, y, r) in enumerate(bombs):
            for j, (x2, y2, _) in enumerate(bombs):
                dx = x - x2
                dy = y - y2
                if j != i and dx * dx + dy * dy <= r * r:
                    G[i].append(j)  # i 可以引爆 j
        def dfs(i):
            for j in G[i]:
                if j not in visited:
                    visited.add(j)
                    dfs(j)
        res=0
        for i in range(n):
            visited=set()
            dfs(i)
            visited.add(i)
            res=max(res,len(visited))
        return res

0722

3226. 使两个整数相等的位更改次数

class Solution:
    def minChanges(self, n: int, k: int) -> int:
        return -1 if (n & k) != k else (n ^ k).bit_count()

3222. 求出硬币游戏的赢家

class Solution {
    public String losingPlayer(int x, int y) {
        int turn = 1;
        while (x >= 1 && y >= 4) {
            turn ^= 1;
            x--;
            y -= 4;
        }
        return turn == 0 ? "Alice" : "Bob";
    }
}

0724

2765. 最长交替子数组

class Solution:
    def alternatingSubarray(self, nums: List[int]) -> int:
        ans = -1
        i, n = 0, len(nums)
        while i < n - 1:
            if nums[i + 1] - nums[i] != 1:
                i += 1  # 直接跳过
                continue
            i0 = i  # 记录这一组的开始位置
            i += 2  # i 和 i+1 已经满足要求,从 i+2 开始判断
            while i < n and nums[i] == nums[i - 2]:
                i += 1
            # 从 i0 到 i-1 是满足题目要求的(并且无法再延长的)子数组
            ans = max(ans, i - i0)
            i -= 1
        return ans 

2766. 重新放置石块

class Solution:
    def relocateMarbles(self, nums: List[int], moveFrom: List[int], moveTo: List[int]) -> List[int]:
        n=len(nums)
        block=set()
        for i in range(n):
            block.add(nums[i])
        for mv in zip(moveFrom,moveTo):
            if mv[0] in block:
                block.remove(mv[0])
            block.add(mv[1])
        
        return sorted(list(block))
class Solution:
    def relocateMarbles(self, nums: List[int], moveFrom: List[int], moveTo: List[int]) -> List[int]:
        st = set(nums)
        for f, t in zip(moveFrom, moveTo):
            st.remove(f)
            st.add(t)
        return sorted(st)
class Solution {
    public List<Integer> relocateMarbles(int[] nums, int[] moveFrom, int[] moveTo) {
        Set<Integer> set= new HashSet<>(nums.length);
        for (int x:nums){
            set.add(x);
        }

        for (int i=0;i<moveFrom.length;i++){
            set.remove(moveFrom[i]);
            set.add(moveTo[i]);
        }

        List<Integer> res=new ArrayList<>(set);
        Collections.sort(res);
        return res;
    }
}

0725

2844. 生成特殊数字的最少操作

class Solution:
    def minimumOperations(self, num: str) -> int:
        n = len(num)
        def f(tail: str) -> int:
            i = num.rfind(tail[1])
            if i <= 0:
                return n
            # 也可以写 num[:i].rfind(tail[0]),但切片需要额外空间
            i = num.rfind(tail[0], 0, i)
            return n if i < 0 else n - i - 2
        return min(n - ('0' in num), f("00"), f("25"), f("50"), f("75"))

0726

2740. 找出分区值

class Solution:
    def findValueOfPartition(self, nums: List[int]) -> int:
        nums.sort()
        res=10**9
        n=len(nums)
        for i in range(1,n):
            res=min(res,nums[i]-nums[i-1])
        return res
//Java
class Solution {
    public int findValueOfPartition(int[] nums) {
        Arrays.sort(nums);
        int res=Integer.MAX_VALUE;
        for (int i=1;i<nums.length;i++){
            res=Math.min(res,nums[i]-nums[i-1]);
        }
        return res;
    }
}

2834. 找出美丽数组的最小和

# 模拟超时
class Solution:
    def minimumPossibleSum(self, n: int, target: int) -> int:
        l=0
        res=0
        for i in range(1,10**9):
            if l==n:
                break
            if target-i < i and target - i >0:
                continue
            else:
                res+=i
                l+=1
        return res%(10**9+7)
# 数学问题
class Solution:
    def minimumPossibleSum(self, n: int, target: int) -> int:
        mod = 10**9 + 7
        m = target // 2
        if n <= m:
            return ((1 + n) * n // 2) % mod
        return ((1 + m) * m // 2 + (target * 2 + (n - m) - 1) * (n - m) // 2) % mod

2580. 统计将重叠区间合并成组的方案数

# 按start_i排序
class Solution:
    def countWays(self, ranges: List[List[int]]) -> int:
        ranges.sort(key=lambda p: p[0])
        m, max_r = 0, -1
        for l, r in ranges:
            if l > max_r:  # 无法合并
                m += 1  # 新区间
            max_r = max(max_r, r)  # 合并
        return pow(2, m, 1_000_000_007)

0727

3106. 满足距离约束且字典序最小的字符串

"""
贪心策略
重点:
26-ord(res[i])+ord('a') >k-cnt不是>=
"""
class Solution:
    def getSmallestString(self, s: str, k: int) -> str:
        n=len(s)
        res=list(s)
        cnt=0
        for i in range(n):
            if cnt==k:
                return ''.join(res)

            if ord(res[i])-ord('a')>13:
                if 26-ord(res[i])+ord('a') >k-cnt:
                    res[i]=chr(ord(res[i])-(k-cnt))
                    cnt=k
                
                else:

                    cnt+=26-ord(res[i])+ord('a')
                    res[i]='a'
                
            else:
                if ord(res[i])-ord('a') >k-cnt:
                    res[i]=chr(ord(res[i])-(k-cnt))
                    cnt=k
                
                else:
                    cnt+=ord(res[i])-ord('a')
                    res[i]='a'
        return ''.join(res)

0728

2779. 数组的最大美丽值

# 和2580相近,本质上都是在找存在部分重叠的区间的最大数
class Solution:
    def maximumBeauty(self, nums: List[int], k: int) -> int:
        nums.sort()
        ans = left = 0
        for right, x in enumerate(nums):
            while x - nums[left] > k * 2:
                left += 1
            ans = max(ans, right - left + 1)
        return ans
//Java
class Solution {
    public int maximumBeauty(int[] nums, int k) {
        Arrays.sort(nums);
        int res=0;
        int left=0;
        for(int i=0;i<nums.length;i++){
            while (nums[i]-nums[left]>2*k){
                left+=1;
            }
            res=Math.max(res,i-left+1);
        }
        return res;
    }
}

0729

682. 棒球比赛

class Solution:
    def calPoints(self, operations: List[str]) -> int:
        record=[]
        def is_number(s):
            try:  # 如果能运行float(s)语句,返回True(字符串s是浮点数)
                float(s)
                return True
            except ValueError:  # ValueError为Python的一种标准异常,表示"传入无效的参数"
                pass  # 如果引发了ValueError这种异常,不做任何事情(pass:不做任何事情,一般用做占位语句)
            try:
                import unicodedata  # 处理ASCii码的包
                unicodedata.numeric(s)  # 把一个表示数字的字符串转换为浮点数返回的函数
                return True
            except (TypeError, ValueError):
                pass
            return False
        for op in operations:
            if is_number(op):
                record.append(int(op))
            if op=="C":
                record.pop()
            if op=="D":
                record.append(2*record[-1])
            if op=="+":
                record.append(record[-1]+record[-2])
        return sum(record)
//Java
class Solution {
    public int calPoints(String[] operations) {
        List<Integer> st = new ArrayList<>();
        for (String op : operations) {
            switch (op.charAt(0)) {
                case '+':
                    st.add(st.get(st.size() - 2) + st.get(st.size() - 1));
                    break;
                case 'D':
                    st.add(st.get(st.size() - 1) * 2);
                    break;
                case 'C':
                    st.remove(st.size() - 1);
                    break;
                default:
                    st.add(Integer.parseInt(op));
            }
        }
        int sum = 0;
        for (int x : st) {
            sum += x;
        }
        return sum;
    }
}

0730

2961. 双模幂运算

//注意这里的重点在于每次计算后都要取模不然会超出限制
class Solution:
    def getGoodIndices(self, variables: List[List[int]], target: int) -> List[int]:
        ans = []
        for i, v in enumerate(variables):
            if pow(pow(v[0], v[1], 10), v[2], v[3]) == target:
                ans.append(i)
        return ans

322. 零钱兑换

# 超出内存限制
class Solution:
    def coinChange(self, coins: List[int], amount: int) -> int:
        if amount==0:
            return 0
        queue=deque([[amount,0]])
        res=10**4
        while queue:
            t,l=queue.popleft()
            for c in coins:
                if t-c==0:
                    res=min(res,l+1)
                
                if t<c:
                    continue
                if t>c:
                    queue.append([t-c,l+1])
            
        if res==10**4:
            return -1
        else:
            return res
class Solution:
    def coinChange(self, coins: List[int], amount: int) -> int:
        @cache
        def dfs(i,c):
            if i<0:
                return 0 if c==0 else inf
            
            if c<coins[i]:
                return dfs(i-1,c)
            
            return min(dfs(i-1,c),dfs(i,c-coins[i])+1)

        res=dfs(len(coins)-1,amount)
        return res if res<inf else -1

2129. 将标题首字母大写

class Solution:
    def capitalizeTitle(self, title: str) -> str:
        word=title.split(' ')
        n=len(word)
        for i in range(n):
            if len(word[i])<=2:
                w=word[i]
                word[i]=w.lower()
            
            else:
                w0=word[i][0]
                w=word[i][1:]
                word[i]= w0.upper()+w.lower()
        return " ".join(word)    

18. 零钱兑换 II

class Solution:
    def change(self, amount: int, coins: List[int]) -> int:
        @cache
        def dfs(i,c):
            if i<0:
                return 1 if c==0 else 0
            
            if c<coins[i]:
                return dfs(i-1,c)
            
            return dfs(i,c-coins[i])+dfs(i - 1, c)

        res=dfs(len(coins)-1,amount)
        return res

2864. 最大二进制奇数

class Solution:
    def maximumOddBinaryNumber(self, s: str) -> str:
        cnt = Counter(s)
        res = ['1'] * (cnt['1'] - 1)
        res.extend(['0'] * cnt['0'])
        res.append('1')
        return "".join(res)

2549. 统计桌面上的不同数字

class Solution:
    def distinctIntegers(self, n: int) -> int:
        nums = [0] * (n + 1)
        nums[n] = 1
        for _ in range(0, n):
            for x in range(1, n + 1):
                if nums[x] == 0:
                    continue
                for i in range(1, n + 1):
                    if x % i == 1:
                        nums[i] = 1
        return sum(nums)

0802

3128. 直角三角形

class Solution:
    def numberOfRightTriangles(self, grid: List[List[int]]) -> int:
        n, m = len(grid), len(grid[0])
        col = [0] * m
        for j in range(m):
            for i in range(n):
                col[j] += grid[i][j]
        res = 0
        for i in range(n):
            row = sum(grid[i])
            for j in range(m):
                if grid[i][j] == 1:
                    res += (row - 1) * (col[j] - 1)
        return res

LCP 40. 心算挑战

class Solution:
    def maxmiumScore(self, cards: List[int], cnt: int) -> int:
        cards.sort()
        n=len(cards)
        res=0
        res+=sum(cards[n-cnt+1:n])
        if res%2==0:
            Flag=True
        else:
            Flag=False
        for i in range(n-cnt,-1,-1): 
            if Flag and cards[i]%2==0:
                res+=cards[i]
                return res
            if not Flag and cards[i]%2!=0:
                res+=cards[i]
                return res
        return 0

0803

3143. 正方形中的最多点数

class Solution:
    def maxPointsInsideSquare(self, points: List[List[int]], s: str) -> int:
        min1 = [inf] * 26
        min2 = inf
        n = len(s)
        for i in range(n):
            x, y = points[i]
            j = ord(s[i]) - ord('a')
            d = max(abs(x), abs(y))
            if d < min1[j]:
                min2 = min(min2, min1[j])
                min1[j] = d
            elif d < min2:
                min2 = d
        return sum(d < min2 for d in min1)

0814

3152. 特殊数组 II

class Solution:
    def isArraySpecial(self, nums: List[int], queries: List[List[int]]) -> List[bool]:
        n = len(nums)
        dp = [1] * n
        for i in range(1, n):
            if (nums[i] ^ nums[i - 1]) & 1 == 1:
                dp[i] = dp[i - 1] + 1
        return [dp[y] >= y - x + 1 for x, y in queries]

3132. 找出与数组相加的整数 II

# 官方题解
class Solution:
    def minimumAddedInteger(self, nums1: List[int], nums2: List[int]) -> int:
        nums1.sort()
        nums2.sort()
        # 枚举保留 nums1[2] 或者 nums1[1] 或者 nums1[0]
        # 倒着枚举是因为 nums1[i] 越大答案越小,第一个满足的就是答案
        for i in range(2, 0, -1):
            x = nums2[0] - nums1[i]
            # 在 {nums1[i] + x} 中找子序列 nums2
            j = 0
            for v in nums1[i:]:
                if nums2[j] == v + x:
                    j += 1
                    # nums2 是 {nums1[i] + x} 的子序列
                    if j == len(nums2):
                        return x
        # 题目保证答案一定存在
        return nums2[0] - nums1[0]

0817

3137. K 周期字符串需要的最少操作次数

class Solution:
    def minimumOperationsToMakeKPeriodic(self, word: str, k: int) -> int:
        n = len(word)
        count = Counter(word[i: i + k] for i in range(0, n, k))
        return n // k - max(count.values())

0818

551. 学生出勤记录 I

class Solution:
    def checkRecord(self, s: str) -> bool:
        n=len(s)
        cnt_A=0
        cnt_L=0
        for i in range(n):
            if s[i]=="P":
                cnt_L=0
                continue
            elif s[i]=="A":
                cnt_A+=1
                if cnt_A==2:
                    return False
                cnt_L=0
            else:
                cnt_L+=1
                if cnt_L==3:
                    return False
        return True    
posted @ 2024-07-06 10:21  zddkk  阅读(8)  评论(0编辑  收藏  举报