LeetcodeLearning - Day 2

Leetcode - 找规律

292.Nim 游戏(Easy)

你和你的朋友,两个人一起玩 Nim 游戏

  • 桌子上有一堆石头。
  • 你们轮流进行自己的回合, 你作为先手
  • 每一回合,轮到的人拿掉 1 - 3 块石头。
  • 拿掉最后一块石头的人就是获胜者。

假设你们每一步都是最优解(不会放水)。请编写一个函数,来判断你是否可以在给定石头数量为 n 的情况下赢得游戏。如果可以赢,返回 true;否则,返回 false

示例 1:

输入:n = 4
输出:false 
解释:以下是可能的结果:
1. 移除1颗石头。你的朋友移走了3块石头,包括最后一块。你的朋友赢了。
2. 移除2个石子。你的朋友移走2块石头,包括最后一块。你的朋友赢了。
3.你移走3颗石子。你的朋友移走了最后一块石头。你的朋友赢了。
在所有结果中,你的朋友是赢家。

示例 2:

输入:n = 1
输出:true

示例 3:

输入:n = 2
输出:true

提示:

  • 1 <= n <= 231 - 1

思路

如果先手是4个石头,必输。如果先手是4的倍数,那么总是可以被后手控制住,即拿完还是4的倍数,最终必输。而先手不是4的倍数,则情况刚好反过来,无论对面怎么拿,我们总是可以采取方案一直使得对手拿时为4的倍数,那么对面必输。(这里的4为可以拿的最大数量+1)

Python

class Solution:
    def canWinNim(self, n: int) -> bool:
        return n % 4 != 0

C++

class Solution {
public:
    bool canWinNim(int n) {
        return n % 4 != 0;
    }
};
319.灯泡开关(Medium)

初始时有 n 个灯泡处于关闭状态。第一轮,你将会打开所有灯泡。接下来的第二轮,你将会每两个灯泡关闭第二个。

第三轮,你每三个灯泡就切换第三个灯泡的开关(即,打开变关闭,关闭变打开)。第 i 轮,你每 i 个灯泡就切换第 i 个灯泡的开关。直到第 n 轮,你只需要切换最后一个灯泡的开关。

找出并返回 n 轮后有多少个亮着的灯泡。

示例 1:

img

输入:n = 3
输出:1 
解释:
初始时, 灯泡状态 [关闭, 关闭, 关闭].
第一轮后, 灯泡状态 [开启, 开启, 开启].
第二轮后, 灯泡状态 [开启, 关闭, 开启].
第三轮后, 灯泡状态 [开启, 关闭, 关闭]. 

你应该返回 1,因为只有一个灯泡还亮着。

示例 2:

输入:n = 0
输出:0

示例 3:

输入:n = 1
输出:1

提示:

  • 0 <= n <= 109

思路

Snipaste_2024-08-28_22-04-57

灯泡在默认关着的情况下,经过奇数次开关后才是开着的。问题可以进一步转换为:哪些数字的因数是奇数个的?一般因数是成对出现,例如n=x*y,只有平方数的会出现x=y,也就是奇数个因数的情况,因此问题抽象为:找到<=n的平方数个数。个数=n开根并向下取整。

Python

class Solution:
    def bulbSwitch(self, n: int) -> int:
        return int(sqrt(n + 0.5))

C++

class Solution {
public:
    int bulbSwitch(int n) {
        return sqrt(n + 0.5);
    }
};
  • 注意这里加了0.5的经验值,通常用于弥补计算精度问题,比如在一些情况下,由于浮点数精度的问题,sqrt(16)计算结果可能会更接近 3.999999...,但实际上它应该是 4 . 通过加0.5可以解决这一点。加太大容易变为向上取整,加太小有时候开根的数太大,加的数在开根后的影响可能因为截断误差而被消除,取0.5较为保险。
  • C++中不需要强转类型是因为函数声明了返回值为int,因此会自动向下取整。而Python的int声明只是为了可读性,没有进行实际的转换,需要人为强转。

对于该问题利用数学归纳法证明如下:

假设结论**“当灯泡数目为**n-1时,经过n-1轮后,最后有剩下floor(sqrt(n-1))**个灯泡是亮着的”**成立,用数学归纳法证明,需要考虑

  1. 灯泡数目为n = 1的情况
  2. 灯泡数目为n的情况

n = 1时,第1个灯泡经过1轮后从关变到开,上述结论显然成立。故证明的重点是,考虑灯泡数目取n时,结论**“当灯泡数目为**n时,经过n轮后,最后有剩下floor(sqrt(n))**个灯泡是亮着的”**是否成立。

当灯泡数目为n时,考虑前n-1个灯泡的行为:

  • 经过n-1轮后,前n-1个灯泡的行为和考虑灯泡数目为n-1时经过n-1轮后的行为是完全一致的,故此时有floor(sqrt(n-1))个灯泡是亮着的。
  • 在第n轮中,只有第n个灯泡进行了切换,故前n-1个灯泡会维持存在floor(sqrt(n-1))个灯泡是亮着的情况。

考虑最后一个灯泡,即第n个灯泡在n轮中的行为。

注意到,当且仅当in的因数时,第n个灯泡在遇到第i轮的时候会切换状态。考虑n的因数个数

  • 若个数为偶数,那么经过偶数次状态转换后,第n个灯泡的状态为
  • 若个数为奇数,那么经过奇数次状态转换后,第n个灯泡的状态为

因数总是成对出现的,假设in的因数,那么n/i一定是n的因数。即灯泡会在第i轮和第n/i轮,都会进行状态切换。

  • i != n/i,那么会进行2次切换。
  • i == n/i,那么仅进行1次切换,即第i轮和第n/i轮属于同一轮。

根据i == n/i可以计算出,i^2 == n。我们可以得出结论:当且仅当n为某个正整数i的平方,即当n为一个完全平方数时,第n个灯泡经过n轮会经过奇数次状态转换,最终的状态为开。

AB是满足A^2 <= n-1 <= B^2A+1 = B成立的两个正整数,即n-1是位于两个相差为1的正整数AB的平方A^2B^2之间的一个整数。显然A = floor(sqrt(n-1))

我们将考虑前n-1个灯泡和第n个灯泡的情况结合起来,计算经过n轮之后状态为开的灯泡的总数。若

  • n不是完全平方数
    • 那么n的最终状态为关,最终亮着的灯泡数为前n-1个灯泡亮着的数目,即floor(sqrt(n-1))
    • 由于n不是完全平方数,那么A^2 <= n-1 < n < B^2成立,此时存在A = floor(sqrt(n))成立,故floor(sqrt(n-1)) = floor(sqrt(n))成立。
    • 因此,对于n个灯泡经过n轮,最终会有floor(sqrt(n))个灯泡亮着,结论成立。
  • n是完全平方数
    • 那么n的最终状态为开,最终亮着的灯泡数为前n-1个灯泡亮着的数目加上第n个灯泡,即floor(sqrt(n-1))+1
    • 由于n是完全平方数,那么A^2 <= n-1 < n = B^2成立,此时存在B = floor(sqrt(n))成立,故floor(sqrt(n-1))+1 = A+1 = B = floor(sqrt(n))成立。
    • 因此,对于n个灯泡经过n轮,最终会有floor(sqrt(n))个灯泡亮着,结论成立。

综合上述两种情况,数学归纳法得证,结论**“当灯泡数目为**n时,经过n轮后,最后有剩下floor(sqrt(n))**个灯泡是亮着的”**成立。

1025.除数博弈(Easy)

爱丽丝和鲍勃一起玩游戏,他们轮流行动。爱丽丝先手开局。

最初,黑板上有一个数字 n 。在每个玩家的回合,玩家需要执行以下操作:

  • 选出任一 x,满足 0 < x < nn % x == 0
  • n - x 替换黑板上的数字 n

如果玩家无法执行这些操作,就会输掉游戏。

只有在爱丽丝在游戏中取得胜利时才返回 true 。假设两个玩家都以最佳状态参与游戏。

示例 1:

输入:n = 2
输出:true
解释:爱丽丝选择 1,鲍勃无法进行操作。

示例 2:

输入:n = 3
输出:false
解释:爱丽丝选择 1,鲍勃也选择 1,然后爱丽丝无法进行操作。

提示:

  • 1 <= n <= 1000

思路

Snipaste_2024-08-29_12-13-09

博弈类的问题常常没有解题思路时,不妨试着写几项试试:

n=1 的时候,区间 (0,1) 中没有整数是 n 的因数,所以此时 Alice 败。
n=2 的时候,Alice 只能拿 1,n 变成 1,Bob 无法继续操作,故 Alice 胜。
n=3 的时候,Alice 只能拿 1,n 变成 2,根据 n=2 的结论,我们知道此时 Bob 会获胜,Alice 败。
n=4 的时候,Alice 能拿 1 或 2,如果 Alice 拿 1,根据 n=3 的结论,Bob 会失败,Alice 会获胜。
n=5 的时候,Alice 只能拿 1,根据 n=4 的结论,Alice 会失败。

大胆猜想:*n* 为奇数的时候 Alice(先手)必败,*n* 为偶数的时候 Alice 必胜

Snipaste_2024-08-29_12-26-06

数学归纳法证明:

n=1 和 n=2 时结论成立。

n>2 时,假设 n≤k 时该结论成立,则 n=k+1 时:

  • 如果 k 为偶数,则 k+1 为奇数,x 是 k+1 的因数,只可能是奇数,而奇数减去奇数等于偶数,且 k+1−x≤k,故轮到 Bob 的时候都是偶数。而根据我们的猜想假设 n≤k 的时候偶数的时候先手必胜,故此时无论 Alice 拿走什么,Bob 都会处于必胜态,所以 Alice 处于必败态。
  • 如果 k 为奇数,则 k+1 为偶数,x 可以是奇数也可以是偶数,若 Alice 减去一个奇数,那么 k+1−x 是一个小于等于 k 的奇数,此时 Bob 占有它,处于必败态,则 Alice 处于必胜态。

综上所述,这个猜想是正确的。

问题转换为:n是否为偶数

Python

class Solution:
    def divisorGame(self, n: int) -> bool:
        return n % 2 == 0

C++

class Solution {
public:
    bool divisorGame(int n) {
        return n % 2 == 0;
    }
};
495.提莫攻击(Easy)

在《英雄联盟》的世界中,有一个叫 “提莫” 的英雄。他的攻击可以让敌方英雄艾希(编者注:寒冰射手)进入中毒状态。

当提莫攻击艾希,艾希的中毒状态正好持续 duration 秒。

正式地讲,提莫在 t 发起攻击意味着艾希在时间区间 [t, t + duration - 1](含 tt + duration - 1)处于中毒状态。如果提莫在中毒影响结束 再次攻击,中毒状态计时器将会 重置 ,在新的攻击之后,中毒影响将会在 duration 秒后结束。

给你一个 非递减 的整数数组 timeSeries ,其中 timeSeries[i] 表示提莫在 timeSeries[i] 秒时对艾希发起攻击,以及一个表示中毒持续时间的整数 duration

返回艾希处于中毒状态的 秒数。

示例 1:

输入:timeSeries = [1,4], duration = 2
输出:4
解释:提莫攻击对艾希的影响如下:
- 第 1 秒,提莫攻击艾希并使其立即中毒。中毒状态会维持 2 秒,即第 1 秒和第 2 秒。
- 第 4 秒,提莫再次攻击艾希,艾希中毒状态又持续 2 秒,即第 4 秒和第 5 秒。
艾希在第 1、2、4、5 秒处于中毒状态,所以总中毒秒数是 4 。

示例 2:

输入:timeSeries = [1,2], duration = 2
输出:3
解释:提莫攻击对艾希的影响如下:
- 第 1 秒,提莫攻击艾希并使其立即中毒。中毒状态会维持 2 秒,即第 1 秒和第 2 秒。
- 第 2 秒,提莫再次攻击艾希,并重置中毒计时器,艾希中毒状态需要持续 2 秒,即第 2 秒和第 3 秒。
艾希在第 1、2、3 秒处于中毒状态,所以总中毒秒数是 3 。

提示:

  • 1 <= timeSeries.length <= 104
  • 0 <= timeSeries[i], duration <= 107
  • timeSeries非递减 顺序排列

思路

分两种情况:

  • 如果在上一次中毒结束了再次中毒,中毒时间+duration。

Snipaste_2024-08-29_13-01-55

  • 如果在还没解毒前再次中毒,则中毒时间增加timeSeries[i] + duration - expired(由于上一段的duration已经加上了,因此只需要加下一段中毒的超过expired的那段即可)

Snipaste_2024-08-29_13-06-47

Python

class Solution:
    def findPoisonedDuration(self, timeSeries: List[int], duration: int) -> int:

        # 结果变量
        ans = 0 

        # 每次中毒结束的时间位置
        expired = 0

        # 遍历数组 timeSeries
        for i in range(len(timeSeries)):

            # 1、如果发现当前的时间大于了最近一次中毒后得结束时间
            if timeSeries[i] >= expired:

                # 又中毒了,叠加时间
                ans += duration
            
            # 2、否则,如果发现当前的时间小于或者等于最近一次中毒后得结束时间
            else:
                # 由于中毒状态不可叠加
                # 新的中毒截止时间是 timeSeries[i] + duration
                # 上次中毒截止时间是 expired
                # 两者相减,获得持续中毒时间
                ans += timeSeries[i] + duration - expired

            # 更新中毒结束的时间位置
            expired = timeSeries[i] + duration
            
        # 返回结果
        return ans

C++

    int ans = 0;
    int expired = 0;
    for (int i = 0; i < timeSeries.size(); ++i)
    {
      // 上次毒已结束
      if (timeSeries[i] >= expired)
      {
        ans += duration;
      }
      // 上次毒还在
      else
      {
        ans += timeSeries[i] + duration - expired;
      }
      expired = timeSeries[i] + duration;
    }
    return ans;

  }
};
747.至少是其他数字两倍的最大数(Easy)

给你一个整数数组 nums ,其中总是存在 唯一的 一个最大整数 。

请你找出数组中的最大元素并检查它是否 至少是数组中每个其他数字的两倍 。如果是,则返回 最大元素的下标 ,否则返回 -1

示例 1:

输入:nums = [3,6,1,0]
输出:1
解释:6 是最大的整数,对于数组中的其他整数,6 至少是数组中其他元素的两倍。6 的下标是 1 ,所以返回 1 。

示例 2:

输入:nums = [1,2,3,4]
输出:-1
解释:4 没有超过 3 的两倍大,所以返回 -1 。

提示:

  • 2 <= nums.length <= 50
  • 0 <= nums[i] <= 100
  • nums 中的最大元素是唯一的

思路

遍历数组,并在遍历过程顺便找一下最大值和第二大值及索引即可。注意找到一个最大值时,对原来记录的最大与第二大值的赋值顺序不能颠倒。

Python

#747. 至少是其他数字两倍的最大数
class Solution:
    def dominantIndex(self, nums: List[int]) -> int:

        # 最大数
        biggest = -1

        # 第二大数
        bigger = -1

        # 最大数所在的索引
        index = 0 

        # 遍历数组 nums
        # i 表示遍历过程中当前元素的索引
        # num 表示遍历过程中当前元素的值
        for i, num in enumerate(nums):

            # 在遍历过程中
            # 如果发现当前元素的值大于了之前找到的最大数
            if num > biggest:
                
                # 1、更新第二大数
                bigger = biggest

                # 2、更新最大数为 num
                biggest = num

                # 注意,千万不能交换上面 1 和 2 代码的顺序

                # 记录最大数的索引
                index = i

            # 否则,发现当前元素的值没有大于之前找到的最大数
            # biggest 不需要更新
            # 如果发现当前元素的值没有大于之前找到的第二大的数
            elif num > bigger:
                # 更新第二大数
                bigger = num

        # 最后,判断一下最大数是否是第二大数的两倍
        # 如果是,则返回最大数的索引 index
        # 否则,返回 -1
        return index if biggest >= bigger * 2 else -1

C++

class Solution {
public:
    int dominantIndex(vector<int>& nums) {
        int m1 = -1, m2 = -1;
        int index = -1;
        for (int i = 0; i < nums.size(); i++) {
            if (nums[i] > m1) {
                m2 = m1;
                m1 = nums[i];
                index = i;
            } else if (nums[i] > m2) {
                m2 = nums[i];
            }
        }
        return m1 >= m2 * 2 ? index : -1; // 三目运算符在Python中是没有的
    }
};

复杂度分析

  • 时间复杂度:O(N),其中 N 是数组的长度。遍历整个数组需要 O(N)。
  • 空间复杂度:O(1)。
1688.比赛中的配对次数

给你一个整数 n ,表示比赛中的队伍数。比赛遵循一种独特的赛制:

  • 如果当前队伍数是 偶数 ,那么每支队伍都会与另一支队伍配对。总共进行 n / 2 场比赛,且产生 n / 2 支队伍进入下一轮。
  • 如果当前队伍数为 奇数 ,那么将会随机轮空并晋级一支队伍,其余的队伍配对。总共进行 (n - 1) / 2 场比赛,且产生 (n - 1) / 2 + 1 支队伍进入下一轮。

返回在比赛中进行的配对次数,直到决出获胜队伍为止。

示例 1:

输入:n = 7
输出:6
解释:比赛详情:
- 第 1 轮:队伍数 = 7 ,配对次数 = 3 ,4 支队伍晋级。
- 第 2 轮:队伍数 = 4 ,配对次数 = 2 ,2 支队伍晋级。
- 第 3 轮:队伍数 = 2 ,配对次数 = 1 ,决出 1 支获胜队伍。
总配对次数 = 3 + 2 + 1 = 6

示例 2:

输入:n = 14
输出:13
解释:比赛详情:
- 第 1 轮:队伍数 = 14 ,配对次数 = 7 ,7 支队伍晋级。
- 第 2 轮:队伍数 = 7 ,配对次数 = 3 ,4 支队伍晋级。 
- 第 3 轮:队伍数 = 4 ,配对次数 = 2 ,2 支队伍晋级。
- 第 4 轮:队伍数 = 2 ,配对次数 = 1 ,决出 1 支获胜队伍。
总配对次数 = 7 + 3 + 2 + 1 = 13

提示:

  • 1 <= n <= 200

思路

方法一:

比较简单的模拟题,直接模拟题目中的赛制流程即可。

class Solution:
    def numberOfMatches(self, n: int) -> int:

        # 结果变量
        ans = 0

        # 不断的配对比赛,直到剩下一支队伍为止
        while n > 1:

            # 1、偶数支队伍
            if n % 2 == 0:

                # 总共进行 n / 2 场比赛
                ans += n // 2 # //为除完向下取整

                # 同时剩下了 n / 2 支队伍
                n //= 2

            # 2、奇数支队伍
            else:
                # 总共进行 ( n - 1 ) / 2 场比赛
                ans += (n - 1) // 2

                # 同时剩下了 (n - 1) / 2 + 1 支队伍
                n = (n - 1) // 2 + 1

        # 获取结果
        return ans

C++

class Solution {
public:
    int numberOfMatches(int n) {
        int ans = 0;
        while (n > 1) {
            if (n % 2 == 0) {
                ans += n / 2;
                n /= 2;
            }
            else {
                ans += (n - 1) / 2;
                n = (n - 1) / 2 + 1;
            }
        }
        return ans;
    }
};

复杂度分析

  • 时间复杂度:O(logn)。每一轮后会有一半(向下取整)数量的队伍无法晋级,因此轮数为 O(logn)。每一轮需要 O(1) 的时间进行计算。

  • 空间复杂度:O(1)。

方法二

数学方法:每一次比赛就会有一个队伍被淘汰,因此为了决出第一名,淘汰了n-1个队,也就是比了n-1次,直接返回n-1即可。

复杂度分析

  • 时间复杂度:O(1)。
  • 空间复杂度:O(1)。

模拟题

【模拟】科大讯飞2023非凡计划-汤姆和杰瑞

题目描述与示例

题目描述

汤姆在集市上买了1公斤奶酪回家。然而,趁汤姆不在时,杰瑞来偷了A/B公斤的奶酪。问杰瑞偷了奶酪后,汤姆还有多少奶酪?

输入描述

第—行给出两个整数A,B1 ≤ A < B ≤ 9

输出描述

输出杰瑞偷了奶酪后,汤姆还有多少奶酪。以分数的形式表示,分子和分母用空格间隔。(输出必须满足分母为B)

示例

输入

2 7

输出

5 7

解题思路

可能是所有真题里面最简单的一题,描述直接,代码简短。 剩下的奶酪为1 - A/B = (B-A)/B,故分别输出B-AB即可。时空复杂度均为1.

注意要点

acm模式下输出是要print出来而不是return的。

Python

A, B = map(int, input().split())
print(B-A, B)

C++

#include <iostream>

using namespace std;

int main() {
    int A, B;
    cin >> A >> B;
    cout << B - A << " " << B << endl;
    return 0;
}
【模拟】OPPO2023秋招提前批-小欧的圆覆盖

题目描述

在平面直角坐标系上有一个矩形,和一个定点P。小欧希望以点P为圆心画一个圆覆盖这个矩形,请你求出圆面积的最小值。注:π3.1415926536

输入

第一行输入四个整数x1,y1,x2,y2,代表矩形左下角坐标为(x1,y1),右上角坐标为(x2,y2)

第二行输入两个整数xp,yp,代表点P的坐标为(xp,yp)

输出

一个浮点数,代表圆的最小面积。如果你的答案和标准答案的相对误差不超过10^-4,则认为你的答案正确。

样例输入

0 0 1 1
0 0

样例输出

6.2831853

思路

本题是非常简单的数学模拟题。为了使得以P为圆心的圆可以覆盖到整个矩形,仅需要枚举圆心P到矩形四个顶点的距离,对四个距离取最大值即可。

image-20240830171823352

Python

from math import sqrt

# 计算两个点(x1, y1)和(x2, y2)的函数
def cal_dis(x1, y1, x2, y2):
    return sqrt((x1-x2)**2 + (y1-y2)**2)


# 表示矩形的两个坐标
x1, y1, x2, y2 = map(int, input().split())
# 点p的坐标
x0, y0 = map(int, input().split())

# 计算圆心p到矩形四个顶点的距离
r1 = cal_dis(x0, y0, x1, y1)
r2 = cal_dis(x0, y0, x1, y2)
r3 = cal_dis(x0, y0, x2, y1)
r4 = cal_dis(x0, y0, x2, y2)

# 四个距离中的最大值,为圆半径的最小值
r = max([r1, r2, r3, r4])

pi = 3.1415926536
# 计算圆面积
print(r*r*pi)

C++

#include <iostream>
#include <iomanip>
#include <cmath>
using namespace std;

double calDis(int x1, int y1, int x2, int y2) {
    return sqrt(pow(x1 - x2, 2) + pow(y1 - y2, 2));
}

int main() {
    int x1, y1, x2, y2, x0, y0;
    cin >> x1 >> y1 >> x2 >> y2 >> x0 >> y0;

    double r1 = calDis(x0, y0, x1, y1);
    double r2 = calDis(x0, y0, x1, y2);
    double r3 = calDis(x0, y0, x2, y1);
    double r4 = calDis(x0, y0, x2, y2);

    double r = max(max(r1, r2), max(r3, r4));

    double pi = 3.1415926536;
    double area = r * r * pi;
    // fixed << setprecision(4)用于调整精度
    // 需要 #include <iomanip>
    cout << fixed << setprecision(4) << area << endl;

    return 0;
}

注意点:

  • 需要记住部分函数使用的库
  • C++ 需要手动指定输出精度来控制小数点后的显示位数。因为 C++ 的输出默认不保留小数点后面的位数,除非特别指定。如果你不指定输出的精度,C++ 可能会只显示整数部分或者显示非常少的小数位数。Python 则通常不需要手动控制,因为它的输出默认保留足够的小数位数来保证结果的准确性。
  • 平方的写法在Python与C++中不同
【模拟】科大讯飞2023非凡计划-数组的最小距离

题目描述

小红定义两个数组ab之间的距离为

∑ i = 0 n − 1 ∣ a i − b i ∣ \sum_{i=0}^{n-1} |a_i-b_i| i=0n1aibi

即每个位置的差的绝对值之和,其中n为数组的长度。小红现在可以进行任意次操作选择任意数组的任意一个元素,使其乘以-1

小红希望最终两个数组的距离尽可能小。你能帮帮她吗?

输入描述

第一行输入一个正整数, 代表两个数组的长度。

第二行输入n个整数ai,代表第一个数组。

第三行输入n个整数bi,代表第二个数组。

输出描述

一个整数,代表两个数组的最小距离。in

示例

输入

3
1 2 3
-3 2 -1

输出

4

思路

由于我们可以任意地选择a数组或b数组中的任意一个元素进行操作,对于第i个位置的两个元素差值a[i]-b[i]而言,通过对a[i]或者b[i]进行乘-1的操作可以获得以下四种情况

  • a[i]-b[i]
  • a[i]+b[i]
  • -a[i]-b[i]
  • -a[i]+b[i]

取绝对值号后,实际上只有两种情况

  • abs(a[i]-b[i]) = abs(-a[i]+b[i])
  • abs(a[i]+b[i]) = abs(-a[i]-b[i])

故总的答案应该为每一个位置的abs(a[i]-b[i])abs(a[i]+b[i])中的较小值,再进行求和。

Python

n = int(input())
# 分别输入两个数组
a = list(map(int, input().split()))
b = list(map(int, input().split()))

# 对于a和b数组中同一个位置的元素ai和bi
# 分别计算abs(ai-bi)和abs(ai+bi)的值
# 取其中的较小值min(abs(ai-bi), abs(ai+bi)加入答案中
ans = sum(min(abs(ai-bi), abs(ai+bi)) for ai, bi in zip(a, b))
print(ans)

C++

#include <iostream>
#include <cmath>
using namespace std;

int main() {
    int n;
    cin >> n;
    
    int a[n], b[n];
    for (int i = 0; i < n; i++) {
        cin >> a[i];
    }
    for (int i = 0; i < n; i++) {
        cin >> b[i];
    }

    int ans = 0; // 记得初始化,否则可能会出现意想不到的结果
    for (int i = 0; i < n; i++) {
        ans += min(abs(a[i] - b[i]), abs(a[i] + b[i]));
    }

    cout << ans << endl;

    return 0;
}

时间复杂度:O(N)。仅需一次遍历数组。

  • 20
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值