LeetCode 题解 | 1.两数之和(最优解)

题目------1.两数之和

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案,并且你不能使用两次相同的元素。

你可以按任意顺序返回答案。

示例 1:

ini 复制代码
输入: nums = [2,7,11,15], target = 9
输出: [0,1]
解释: 因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。

示例 2:

ini 复制代码
输入: nums = [3,2,4], target = 6
输出: [1,2]

示例 3:

ini 复制代码
输入: nums = [3,3], target = 6
输出: [0,1]

提示:

  • 2 <= nums.length <= 104
  • -109 <= nums[i] <= 109
  • -109 <= target <= 109
  • 只会存在一个有效答案

二、小白题解(正是本人)

js 复制代码
/**

 * @param {number[]} nums

 * @param {number} target

 * @return {number[]}

 */

var twoSum = function(nums, target) {

    for(let i=0;i<nums.length;i++){

        for(let j=i+1;j<nums.length;j++){

            if(nums[i]+nums[j]===target){

                return [i,j];

            }

        }

    }

};

这个解题思路有很多缺点------ 时间复杂度高没有异常处理看上去像作者自己写的......

总之就是一个暴力题解,我们在最坏的情况下是 <math xmlns="http://www.w3.org/1998/Math/MathML"> N ( O 2 ) N(O2) </math>N(O2)的时间复杂度,会将nums中的所有元素组合遍历知道找到符合条件的两个元素的下标,那么有没有更好的解法呢?

三、有的兄弟,肯定有的(时间复杂度上的最优解)

js 复制代码
/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number[]}
 */
function twoSum(nums, target) {
    const numMap = {};
    for (let i = 0; i < nums.length; i++) {
        const complement = target - nums[i];
        if (complement in numMap) {
            return [numMap[complement], i];
        }
        numMap[nums[i]] = i;
    }
    return []; 
}

这个解法用到了哈希表 ,这里我们并不需要去详细研究哈希表是个什么东西,我们这里可以把哈希表理解为一个容器,里面的数据可以拿出来和我们想要的目标数据对比,每次对比是 <math xmlns="http://www.w3.org/1998/Math/MathML"> N ( O ) N(O) </math>N(O)的复杂度。

我们来看题解的主体

js 复制代码
 for (let i = 0; i < nums.length; i++) {
        const complement = target - nums[i];
        if (complement in numMap) {
            return [numMap[complement], i];
        }
        numMap[nums[i]] = i;
    }

1.每个元素遍历了几次?

我们只有一个for循环,这意味着每个数组里面的元素只会遍历一遍

2.每个元素遍历经历了什么

存入哈希表之前

1.被用作计算和自己组合起来符合题意的元素的值

js 复制代码
const complement = target - nums[i];

2.被存储在哈希表中作为键值存储在哈希表中,同时下表作为对应键值的值

js 复制代码
numMap[nums[i]] = i;

存入哈希表之后

3.作为可被寻找的、其他元素的"另一半",如果确定是,则输出两元素在原数组的下标

js 复制代码
 if (complement in numMap) {
            return [numMap[complement], i];
        }

四、下面我们用一个例子来分析最优解的执行过程

js 复制代码
nums = [2,7,11,15];
target = 9

具体过程如下(图解)

五、可执行流程(将代码复杂到编译器运行即可得到动态图解)

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>两数之和 - 哈希表解法示意图</title>
    <style>
        body {
            font-family: 'Arial', sans-serif;
            max-width: 800px;
            margin: 0 auto;
            padding: 20px;
            background-color: #f5f7fa;
        }
        .container {
            background: white;
            border-radius: 10px;
            padding: 20px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
        }
        h1 {
            color: #2c3e50;
            text-align: center;
        }
        .visualization {
            display: flex;
            flex-direction: column;
            gap: 20px;
            margin-top: 30px;
        }
        .array-container {
            display: flex;
            justify-content: center;
            position: relative;
            height: 100px;
        }
        .array-element {
            width: 60px;
            height: 60px;
            background: #3498db;
            color: white;
            display: flex;
            align-items: center;
            justify-content: center;
            border-radius: 5px;
            margin: 0 5px;
            position: relative;
            transition: all 0.3s;
            font-weight: bold;
        }
        .array-index {
            position: absolute;
            top: -20px;
            color: #7f8c8d;
            font-size: 12px;
        }
        .hash-table {
            display: flex;
            flex-wrap: wrap;
            gap: 10px;
            justify-content: center;
            min-height: 120px;
            background: #ecf0f1;
            padding: 15px;
            border-radius: 5px;
        }
        .hash-entry {
            background: #2ecc71;
            color: white;
            padding: 8px 12px;
            border-radius: 5px;
            display: flex;
            flex-direction: column;
            align-items: center;
            opacity: 0;
            transform: scale(0.8);
            transition: all 0.5s;
        }
        .hash-entry.visible {
            opacity: 1;
            transform: scale(1);
        }
        .hash-key {
            font-weight: bold;
            border-bottom: 1px solid white;
            margin-bottom: 3px;
            padding-bottom: 3px;
        }
        .current {
            box-shadow: 0 0 0 3px #e74c3c;
            transform: scale(1.1);
        }
        .complement {
            background: #e74c3c;
        }
        .found {
            background: #f39c12;
            animation: pulse 0.5s 2;
        }
        @keyframes pulse {
            0% { transform: scale(1); }
            50% { transform: scale(1.1); }
            100% { transform: scale(1); }
        }
        .explanation {
            background: #f8f9fa;
            padding: 15px;
            border-radius: 5px;
            margin-top: 20px;
            border-left: 4px solid #3498db;
        }
        .controls {
            display: flex;
            justify-content: center;
            gap: 10px;
            margin-top: 20px;
        }
        button {
            padding: 8px 15px;
            background: #3498db;
            color: white;
            border: none;
            border-radius: 5px;
            cursor: pointer;
            transition: background 0.3s;
        }
        button:hover {
            background: #2980b9;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>两数之和 - 哈希表解法示意图</h1>
        <div class="visualization">
            <div class="array-container">
                <!-- 数组元素将通过JS动态生成 -->
            </div>
            <div class="hash-table">
                <!-- 哈希表内容将通过JS动态生成 -->
            </div>
        </div>
        <div class="explanation">
            <p><strong>当前步骤说明:</strong> <span id="step-explanation">初始化数组和哈希表</span></p>
            <p><strong>算法原理:</strong> 遍历数组,对于每个元素计算 complement = target - nums[i],检查 complement 是否存在于哈希表中。</p>
        </div>
        <div class="controls">
            <button id="prev-btn">上一步</button>
            <button id="next-btn">下一步</button>
            <button id="reset-btn">重置</button>
        </div>
    </div>

    <script>
        // 示例数据
        const nums = [2, 7, 11, 15];
        const target = 9;
        let currentStep = 0;
        let hashMap = {};
        
        // 初始化可视化
        function initVisualization() {
            const arrayContainer = document.querySelector('.array-container');
            arrayContainer.innerHTML = '';
            
            // 创建数组元素
            nums.forEach((num, index) => {
                const element = document.createElement('div');
                element.className = 'array-element';
                element.textContent = num;
                element.id = `num-${index}`;
                
                const indexLabel = document.createElement('div');
                indexLabel.className = 'array-index';
                indexLabel.textContent = index;
                
                element.appendChild(indexLabel);
                arrayContainer.appendChild(element);
            });
            
            updateHashTable();
            updateExplanation();
        }
        
        // 更新哈希表显示
        function updateHashTable() {
            const hashTable = document.querySelector('.hash-table');
            hashTable.innerHTML = '';
            
            for (const [key, value] of Object.entries(hashMap)) {
                const entry = document.createElement('div');
                entry.className = 'hash-entry visible';
                entry.innerHTML = `
                    <div class="hash-key">${key}</div>
                    <div>→ ${value}</div>
                `;
                hashTable.appendChild(entry);
            }
        }
        
        // 更新步骤说明
        function updateExplanation() {
            const explanation = document.getElementById('step-explanation');
            const currentElement = document.getElementById(`num-${currentStep}`);
            const elements = document.querySelectorAll('.array-element');
            
            // 重置所有元素样式
            elements.forEach(el => {
                el.classList.remove('current', 'complement', 'found');
            });
            
            switch(currentStep) {
                case 0:
                    explanation.textContent = "开始遍历数组,当前元素 nums[0] = 2";
                    currentElement.classList.add('current');
                    break;
                case 1:
                    explanation.textContent = "计算 complement = 9 - 2 = 7,7 不在哈希表中,将 2 存入哈希表";
                    currentElement.classList.add('current');
                    break;
                case 2:
                    explanation.textContent = "移动到 nums[1] = 7,计算 complement = 9 - 7 = 2";
                    currentElement.classList.add('current');
                    document.getElementById('num-0').classList.add('complement');
                    break;
                case 3:
                    explanation.textContent = "发现 2 在哈希表中(索引 0),找到解 [0, 1]!";
                    currentElement.classList.add('current');
                    document.getElementById('num-0').classList.add('found');
                    currentElement.classList.add('found');
                    break;
                default:
                    explanation.textContent = "遍历完成";
            }
        }
        
        // 下一步
        function nextStep() {
            if (currentStep >= 4) return;
            
            switch(currentStep) {
                case 0:
                    // 准备处理第一个元素
                    break;
                case 1:
                    // 处理 nums[0] = 2
                    hashMap[nums[0]] = 0;
                    break;
                case 2:
                    // 处理 nums[1] = 7
                    const complement = target - nums[1];
                    if (complement in hashMap) {
                        // 找到解的情况
                    }
                    break;
                case 3:
                    // 完成
                    break;
            }
            
            currentStep++;
            updateHashTable();
            updateExplanation();
        }
        
        // 上一步
        function prevStep() {
            if (currentStep <= 0) return;
            
            currentStep--;
            
            // 回退哈希表状态
            if (currentStep < 1) {
                hashMap = {};
            } else if (currentStep < 2) {
                hashMap = { [nums[0]]: 0 };
            }
            
            updateHashTable();
            updateExplanation();
        }
        
        // 重置
        function reset() {
            currentStep = 0;
            hashMap = {};
            initVisualization();
        }
        
        // 事件监听
        document.getElementById('next-btn').addEventListener('click', nextStep);
        document.getElementById('prev-btn').addEventListener('click', prevStep);
        document.getElementById('reset-btn').addEventListener('click', reset);
        
        // 初始化
        initVisualization();
    </script>
</body>
</html>

六、结语

再见!

相关推荐
学渣y14 分钟前
React状态管理-对state进行保留和重置
javascript·react.js·ecmascript
明月看潮生23 分钟前
青少年编程与数学 02-019 Rust 编程基础 09课题、流程控制
开发语言·算法·青少年编程·rust·编程与数学
oioihoii31 分钟前
C++23 views::slide (P2442R1) 深入解析
linux·算法·c++23
_龙衣34 分钟前
将 swagger 接口导入 apifox 查看及调试
前端·javascript·css·vue.js·css3
yuhao__z1 小时前
代码随想录算法训练营第六十三天| 图论9—卡码网47. 参加科学大会,94. 城市间货物运输 I
算法·图论
进取星辰1 小时前
25、Tailwind:魔法速记术——React 19 样式新思路
前端·react.js·前端框架
June`1 小时前
专题三:穷举vs暴搜vs深搜vs回溯vs剪枝(全排列)决策树与递归实现详解
c++·算法·深度优先·剪枝
vlln2 小时前
适应性神经树:当深度学习遇上决策树的“生长法则”
人工智能·深度学习·算法·决策树·机器学习
struggle20252 小时前
continue通过我们的开源 IDE 扩展和模型、规则、提示、文档和其他构建块中心,创建、共享和使用自定义 AI 代码助手
javascript·ide·python·typescript·开源
x-cmd2 小时前
[250512] Node.js 24 发布:ClangCL 构建,升级 V8 引擎、集成 npm 11
前端·javascript·windows·npm·node.js