击败了90%的解法?Two Sum 从 O(n²) 到 O(n) 的优化之路

同样是 Two Sum,暴力解法耗时 56ms,而哈希解法仅需 2ms,差距在哪?

话不多说,先上图

下图为暴力解法

图1-1

下图为暴力解法的代码

js 复制代码
public class TwoSum {
    public int[] twoSum(int[] nums, int target) {
        // 外层循环:遍历每个元素作为第一个数
        for (int i = 0; i < nums.length; i++) {
            // 内层循环:遍历当前元素之后的所有元素(避免重复计算)
            for (int j = i + 1; j < nums.length; j++) {
                // 判断两数之和是否等于目标值
                if (nums[i] + nums[j] == target) {
                    // 找到则返回两个元素的下标
                    return new int[]{i, j};
                }
            }
        }
        // 题目假设一定有解,此处可根据实际需求返回null或抛出异常
        return null;
    }
}

下图为借助HashMap实现的

图1-3
下图为借助**HashMap**实现的代码

class 复制代码
    public int[] twoSum(int[] nums, int target) {
        HashMap<Integer,Integer>sumMap=new HashMap<>();
        //这里第一个Integer是nums[i]
        //第二个Integer是i(数组的索引值)
        for(int i=0;i< nums.length;i++){
            //这里的complement指的是目标值和当前遍历的值的差值
            int complement=target-nums[i];
            if(sumMap.containsKey(complement)){
                return new int[]{sumMap.get(complement),i};
            }
            //如果在sumMap中没有找到与nums[i]和为target的值
            // 那就把当前的值和对应的索引放在sumMap里,
            //为了给后面还没有遍历到的元素做匹配存储
            sumMap.put(nums[i],i);
        }
        return null;
    }
}

作为"小趴菜"的我第一眼看到这个题目,想到的就是暴力解法

这种方法容易想到而且好理解,但总觉得不对劲------如果数组很长,这代码岂不是要跑半天?比如说当数组长度 n=10⁵ 时,暴力解法需要计算 10¹⁰ 次,直接超时!而且效率极低!所以此方法绝不是最佳。其实这题藏着哈希表最核心的用法:用空间换时间,把"找元素"的效率从O(n)压到O(1)。

暴力解法 和利用HashMap解法的主要区别:

想找和为target的另一个数,其实就是找target - nums[i]。暴力法是一个个问(遍历),而哈希表像个"通讯录"------把见过的数和它的下标记下来,下次需要时直接查(不用再遍历)。比如 nums = [2,7,11,15],target=9:

  • 当i=0(nums[i]=2),需要找9-2=7,查通讯录(目前为空),就把2和下标0存进去;

  • 当i=1(nums[i]=7),需要找9-7=2,查通讯录------哎,2在里面!直接返回[0,1]。

  • 图1-4中 map.containsKey(complement) :"这一步就是'查通讯录',时间复杂度O(1)";

下表展示两种解法复杂度区别以及使用场景

方法 时间复杂度 空间复杂度 适用场景
暴力循环 O(n²) O(1) 数组极短的情况(n<1k)
哈希表 O(n) O(n) 大部分场景(n>1w)

除了这两种解法,是否还有其他解法。

答案是肯定的

它就是"双指针解法"

但是使用这种解法是有前提的。已排序数组 是双指针优化的关键前提!如果题目给定的数组是升序排列 (如 [2, 7, 11, 15]),可以直接用双指针将时间复杂度优化到 O(n) ,且空间复杂度为 O(1)(无需额外哈希表)。

上代码:

`public int[] twoSum(int[] nums, int target) {

sql 复制代码
int left = 0, right = nums.length - 1;
while (left < right) {
    int sum = nums[left] + nums[right];
    if (sum == target) {
        return new int[]{left, right}; // 返回索引
    } else if (sum < target) {
        left++; // 和太小,左指针右移
    } else {
        right--; // 和太大,右指针左移
    }
}
return null; // 无解

}`

  • 时间复杂度 :O(n)
    • 双指针最多遍历整个数组一次(如最坏情况下 leftright 相遇)。
  • 空间复杂度 :O(1)
    • 仅用两个指针变量,无额外空间。

以下是三种解法复杂度表

解法 时间复杂度 空间复杂度 适用场景
暴力双重循环 O(n²) O(1) 无序数组,数据量小(n<1k)
哈希表 O(n) O(n) 无序数组,数据量大 (n>1w)
双指针 O(n) O(1) 已排序数组

一定要注意!!!使用双指针的前提是已排序的数组

最后关于三数之和的复杂度,想和掘友们聊聊:暴力是O(n³),排序+双指针是O(n²) ,理论上哈希表也能做(存两数和),但实际为啥很少用哈希法?是空间换时间不划算,还是去重逻辑太复杂?大家在项目里遇到类似三数问题,优先选哪种思路?

有任何疑问,或者有其他优化思路,欢迎在评论区讨论~

欢迎大佬们不吝赐教~

感谢观看!

相关推荐
CoovallyAIHub30 分钟前
YOLO + DeepSort 的视频目标检测与跟踪全解析
深度学习·算法·计算机视觉
CoovallyAIHub1 小时前
基于YOLOv10-MHSA的“三北”工程内蒙古地区植树位点精准检测研究
深度学习·算法·计算机视觉
云和数据.ChenGuang3 小时前
Raft协议 一种专为分布式系统设计的共识算法
运维·服务器·算法·区块链·共识算法
重生之我是Java开发战士4 小时前
【数据结构】深入理解顺序表与通讯录项目的实现
数据结构·算法
anlogic4 小时前
Java基础 8.11
java·开发语言·算法
sjh21006 小时前
STM32的计数模式和pwm模式
java·stm32·算法
dlraba80212 小时前
机器学习-----K-means算法介绍
算法·机器学习·kmeans
啊阿狸不会拉杆13 小时前
《算法导论》第 14 章 - 数据结构的扩张
数据结构·c++·算法·排序算法
Q741_14714 小时前
如何判断一个数是 2 的幂 / 3 的幂 / 4 的幂 / n 的幂 位运算 总结和思考 每日一题 C++的题解与思路
开发语言·c++·算法·leetcode·位运算·总结思考
小王爱学人工智能14 小时前
快速了解DBSCAN算法
算法·机器学习·支持向量机