击败了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²) ,理论上哈希表也能做(存两数和),但实际为啥很少用哈希法?是空间换时间不划算,还是去重逻辑太复杂?大家在项目里遇到类似三数问题,优先选哪种思路?

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

欢迎大佬们不吝赐教~

感谢观看!

相关推荐
mit6.82417 分钟前
bfs|栈
算法
CoderYanger1 小时前
优选算法-栈:67.基本计算器Ⅱ
java·开发语言·算法·leetcode·职场和发展·1024程序员节
jllllyuz2 小时前
Matlab实现基于Matrix Pencil算法实现声源信号角度和时间估计
开发语言·算法·matlab
稚辉君.MCA_P8_Java2 小时前
DeepSeek 插入排序
linux·后端·算法·架构·排序算法
多多*2 小时前
Java复习 操作系统原理 计算机网络相关 2025年11月23日
java·开发语言·网络·算法·spring·microsoft·maven
.YM.Z3 小时前
【数据结构】:排序(一)
数据结构·算法·排序算法
Chat_zhanggong3453 小时前
K4A8G165WC-BITD产品推荐
人工智能·嵌入式硬件·算法
百***48073 小时前
【Golang】slice切片
开发语言·算法·golang
墨染点香3 小时前
LeetCode 刷题【172. 阶乘后的零】
算法·leetcode·职场和发展
做怪小疯子4 小时前
LeetCode 热题 100——链表——反转链表
算法·leetcode·链表