「LeetCode」1346.检查整数及其两倍数是否存在

218 阅读2分钟

「这是我参与2022首次更文挑战的第25天,活动详情查看:2022首次更文挑战」。

题目描述🌍

给你一个整数数组 arr,请你检查是否存在两个整数 NM,满足 NM 的两倍(即,N = 2 * M)。

更正式地,检查是否存在两个下标 ij 满足:

  • i != j
  • 0 <= i, j < arr.length
  • arr[i] == 2 * arr[j]

示例 1

输入:arr = [10,2,5,3]
输出:true
解释:N = 10 是 M = 5 的两倍,即 10 = 2 * 5

示例 2

输入:arr = [7,1,14,11]
输出:true
解释:N = 14 是 M = 7 的两倍,即 14 = 2 * 7

示例 3

输入:arr = [3,1,7,11]
输出:false
解释:在该情况下不存在 N 和 M 满足 N = 2 * M 。

提示

  • 2 <= arr.length <= 500
  • 103-10^3 <= arr[i] <= 10310^3

暴力求解🌖

解题思路

双重循环直接带走,需要注意的是判断条件要双向判断

代码

Java

class Solution {
    public boolean checkIfExist(int[] arr) {
        int length = arr.length;
        for (int i = 0; i < length - 1; i++) {
            for (int j = i + 1; j < length; j++) {
                // 双向判断
                if (arr[j] == 2 * arr[i] || arr[i] == 2 * arr[j])
                    return true;
            }
        }
        return false;
    }
}

C++

class Solution {
public:
    bool checkIfExist(vector<int> &arr) {
        int length = arr.size();
        for (int i = 0; i < length - 1; ++i) {
            for (int j = i + 1; j < length; ++j) {
                if (arr[j] == 2 * arr[i] || arr[i] == 2 * arr[j])
                    return true;
            }
        }
        return false;
    }
};

时间复杂度:O(n2)O(n^2)

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

排序 & 双指针法🚀

解题思路

你会想,可以排序后遍历数组,当 arr[b] = 2 * arr[a] (b > a) 时,不就可以判断了吗?

不对。因为本题中说的是整数,所以有可能是正整数、负整数和零,所以将这些纳入考虑的话,可以使用双指针完成 2 轮一次遍历

设指针 i 用于遍历数组元素 x,指针 j 用于查找 2x.

对于 x>0x>0 的情况,指针只需要一直前进。若 j 在前进过程中找到一个比 2x 大的数字,那么 2x 必然不存在。在 i 前进的过程中 i 所指向的 x 会不断递增,2x 也会不断递增,因此指针 j 不需要后退。

对于 x<0x<0 的情况,指针只需要一直后退。若 j 在后退过程中找到一个比 2x 小的数字,那么 2x 必然不存在。在 i 后退的过程中 p 所指向的 x 会不断递减,2x 也会不断递减,因此指针 j 不需要前进。

代码

Java

class Solution {
    public boolean checkIfExist(int[] arr) {
        Arrays.sort(arr);
        // 2 <= arr.length <= 500
        int length = arr.length;
        // 判断>0部分: 交替前进
        for (int i = 0, j = i + 1; i != length - 1; i++) {
            while (j < length && arr[i] * 2 > arr[j])
                j++;
            if (j < length && arr[i] * 2 == arr[j] && i != j)
                return true;
        }

        // 判断<0部分: 交替后退
        for (int i = length - 1, j = i - 1; i != 0; i--) {
            while (j >= 0 && arr[i] * 2 < arr[j])
                j--;
            if (j >= 0 && arr[i] * 2 == arr[j] && i != j)
                return true;
        }

        return false;
    }
}

C++

class Solution {
public:
    bool checkIfExist(vector<int> &arr) {
        sort(arr.begin(), arr.end());
        int length = arr.size();
        // judge '>0' part
        for (int i = 0, j = i + 1; i < length - 1; ++i) {
            while (j < length - 1 && arr[j] < arr[i] * 2)
                j++;
            if (arr[j] == arr[i] * 2 && i != j)
                return true;
        }
        // judge '<0' part
        for (int i = length - 1, j = i - 1; i > 0; --i) {
            while (j > 0 && arr[j] > arr[i] * 2)
                j--;
            if (arr[j] == arr[i] * 2 && i != j)
                return true;
        }
        return false;
    }
};

时间复杂度:O(nlogn)O(n·logn),排序时间复杂度 O(nlogn)O(n·logn),而双指针遍历的时间复杂度为 O(n)O(n)

空间复杂度:O(logn)O(logn)

哈希法🧩

解题思路

在数组中查找两个存在某种关联的数字,这不就和「两数之和」的思路很像吗?!

看不懂解题思路的话,可以看链接中「两数之和」哈希法的求解过程!

唯一需要注意的是:需要添加当前遍历元素 num2 倍数1/2 倍数,才能让后面的元素完全判断。

代码

Java

class Solution {
    public boolean checkIfExist(int[] arr) {
        Set<Integer> hashSet = new HashSet<>();
        for (int num : arr) {
            // 判断该数的2倍或1/2倍是否存在
            if (hashSet.contains(num))
                return true;
            // num可能是某个数的1/2
            hashSet.add(num * 2);
            if (num % 2 == 0)
                // num可能是某个数的2倍(当且仅当num为偶数)
                hashSet.add(num / 2);
        }
        return false;
    }
}

C++

class Solution {
public:
    bool checkIfExist(vector<int> &arr) {
        unordered_set<int> unorderedSet;
        for (int num: arr) {
            if (unorderedSet.find(num) != unorderedSet.end())
                return true;
            unorderedSet.insert(num * 2);
            if (num % 2 == 0)
                unorderedSet.insert(num / 2);
        }
        return false;
    }
};

时间复杂度:O(n)O(n)

空间复杂度:O(n)O(n)

最后🌅

该篇文章为 「LeetCode」 系列的 No.23 篇,在这个系列文章中:

  • 尽量给出多种解题思路
  • 提供题解的多语言代码实现
  • 记录该题涉及的知识点

👨‍💻争取做到 LeetCode 每日 1 题,所有的题解/代码均收录于 「LeetCode」 仓库,欢迎随时加入我们的刷题小分队!