1.2 Leetcode 练习——两数之和 第一题 使用 JavaScript 语言

本文解析了LeetCode经典问题1.2两数之和的解法,通过哈希表的数据结构,展示了如何在JavaScript中利用空间换时间,快速找到数组中和为目标值的两个数及其下标。实例演示和代码解析有助于理解哈希表在搜索问题中的高效应用。
摘要由CSDN通过智能技术生成

Leetcode 练习 1.2

两数之和 第一题

题目:

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

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

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

示例 1:
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。

示例 2:
输入:nums = [3,2,4], target = 6
输出:[1,2]

示例 3:
输入:nums = [3,3], target = 6
输出:[0,1]

提示:

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


以下是以相关解答,暂不要求多种方法

解题思路:
哈希表:
1. 遍历的同时,记录一些信息,省去一层循环。【以空间换时间】
2. 需要记录已经遍历过的数值和它对应的下标,借助查表实现。

使用 JavaScript 语言:

解法一:

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number[]}
 */

var twoSum = function(nums, target) {
// 以上为leetcode 上所给的格式

  let hash = {};
  for (let i = 0; i < nums.length; i++) {
    if (hash[target - nums[i]] !== undefined) {
      return [i, hash[target - nums[i]]];
    }
    hash[nums[i]] = i;
  }
  return [];
  
};

解法2:

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number[]}
 */
var twoSum = function(nums, target) {
// 以上为leetcode 上所给的格式
	
	let len = nums.length;
	
	//创建 MAP
	const MAP = new Map();
	
	// 由于第一个元素在它之前一定没有元素与之匹配,所以先存入哈希表
	MAP.set(nums[0],0);
	for(len i=1;i < len ; i++){
		//提取共用
		let other = target - nums[i];
		
		//判断是否符合条件,返回对应的下标
		if(MAP.get(other) !== undefined) return [MAP.get(other),i];
		
		// 不符合的存入hash表
		MAP.set(nums[i],i)
	}
};

代码运行结果:
使用javascript语言来解两数之和


关于JavaScript代码进行分析:


1号代码块:
let hash = { };

ES2015 引入了两个重要的 JavaScript 新关键词:let 和 const
这两个关键字在 JavaScript 中提供了 块作用域(Block Scope)变量(和常量)
在ES2015 之前,JavaScript 只有两种类型的作用域: 全局作用域函数作用域


全局作用域

全局(在函数之外)声明的变量拥有全局作用域
全局变量在JavaScript 程序中的任何位置访问。

var carName = "porsche";
	// 此处的代码可以使用 carName

function myFunction(){
	// 此处的代码也可以使用 carName
}

如果在块外声明,那么varlet 也很相似
它们都拥有全局作用域

var x = 10;    //全局作用域
let y = 10;    //全局作用域

函数作用域

局部(函数内)声明的变量拥有函数作用域
局部变量只能在他们被声明的函数内访问。

// 此处的代码不可以使用 carName
function myFunction(){
	var carName = "porsche"
	// code here CAN use carName
}
	// 此处的代码不可以使用 carName

在函数内声明变量时,使用varlet很相似
它们都有函数作用域

function myFunction(){
	var carName = "porsche" ;   // 函数作用域
}

function myFunction(){
	let varName = "porsche" ;   // 函数作用域
}

JavaScript 块作用域

通过 var 关键词声明的变量没有块作用域
在块 **{ }**内声明的变量可以从块之外进行访问

{
	var x = 10;
}
// 此处可以使用 x

在 ES2015 之前,JavaScript 是没有块作用域的
可以使用 let 关键词声明拥有块作用域的变量

在块 { } 内声明的变量无法从块外访问:

{
	let x = 10;
}
// 此处不可以使用 x

重新声明变量

使用 var 关键字重新声明变量会带来问题

在块中重新声明变量也将重新声明块外的变量:

var x = 10;
// 此处 x 为 10 
{
	var x = 6;
	// 此处 x 为 6
}
// 此处 x 为6

使用let 关键字重新声明变量可以解决上面的问题

在块中重新声明变量不会重新声明块外的变量:

var x = 10 ;
// 此处 x 为 10
{
	let x = 6 ;
	// 此处 x 为 6
}
// 此处 x 为 10

重新声明

  1. 运行在程序的任何位置使用 var 重新声明 JavaScript 变量
  2. 在相同的作用域,或在相同的块中,通过 let 重新声明一个 var 变量是不允许的
  3. 在相同的作用域,或在相同的块中,通过 let 重新声明一个 let 变量是不允许的
  4. 在相同的作用域,或在相同的块中,通过 var 重新声明一个 let 变量是不允许的
  5. 在不同的作用域或块中,通过 let 重新声明变量是允许的

提升
通过 var 声明的变量会提升(Hoisting)到顶端。

  • 可以在声明变量之前就使用它
  • 通过 let 定义的变量不会提升到顶端
  • 在声明 let 变量之前就使用它会导致 ReferenceError
  • 变量从块的开头一直处于“暂时死区”,直到声明为止

循环作用域

在循环中使用 var

var i = 7 ;
for (var i = 0; i < 10 ;i++ ) {
	// 一些语句
}
// 此处,i为10

在循环中使用 let

let i= 7;
for (let i = 0 ; i <10 ; i++ ){
	//一些语句
}
// 此处 i 为 7

在第一个例子中,在循环中使用的变量使用var 重新声明了循环之外的变量
在第二个例子中,在循环中使用的变量使用let 并没有重新声明循环外的变量。
如果在循环中用let 声明了变量 i ,那么只有在循环内,变量 i 才是可见的。


HTML 中的全局变量

使用 JavaScript 的情况下,全局作用域是 JavaScript 环境。
在 HTML 中,全局作用域是window 对象

通过 var 关键词定义的全局变量属于 window 对象:

var carName = "porsche" ;
// 此处的代码可以使用 window.crName

通过let关键词定义的全局变量不属于 window 对象:

let carName = "porsche";
// 此处的代码不可使用 window.carName


2号代码块:
if (hash[target - nums[i]] !== undefined){ 
	return [i,hash[target - nums[i]]];
}
hash[nums[i]] = i;
/*
	通过算出差值给hash 用作键名匹配是否存在
	不存在就以 nums 的值为键,以下标为值保存用以下次匹配
	直到在hash中匹配到差值的键
	则返回当前的 i 与 hash 差的值
*/
哈希表最大的优点:

就是把数据的存储和查找消耗的时间大大降低,几乎可以看成是常数时间;而代价仅仅是消耗比较多的内存。
然而在当前可利用内存越来越多的情况下,用空间换时间的做法是值得的。(用内存换取更快的查找速度)

基本原理:

使用一个下标范围比较大的数组来存储元素。
可以设计一个函数(哈希函数,也叫做散列函数),使得每个元素的关键字都与一个函数值(即数组下标,hash值)相对应,于是用这个数组单元来存储这个元素。
也可以简单的理解为,按照关键字为每一个元素“分类”,然后将这个元素存储在相应“类”所对应的地方,称为桶。

两大特点:

不能够保证每个元素的关键字与函数值是一一对应的,因此极有可能出现对于不同的元素,却计算出了相同的函数值,这样就产生了“冲突”,换句话说,就是把不同的元素分在了相同的“类”之中。
总的来说,“直接定址”与“解决冲突”是哈希表的两大特点。

插入和取值过程:

hash_map,首先分配一大片内存,形成许多桶。是利用hash函数,对key进行映射到不同区域(桶)进行保存。

插入过程:
  1. 得到key
  2. 通过hash函数得到hash值
  3. 得到桶号(一般都为hash值对桶数求模)
  4. 存放key和value在桶内(hashtable[nums[i]]=i)
取值过程:
  1. 得到key
  2. 通过hash函数得到hash值
  3. 得到桶号(一般都为hash值对桶数求模)
  4. 比较桶的内部元素是否与key相等,若都不相等,则没有找到。
  5. 取出相等的记录的value。(auto it = hashtable.find(target-nums[i]);if(it!=hashtable.end(){return it->second;//找到了}))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值