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代码进行分析:
1号代码块:
let hash = { };
ES2015 引入了两个重要的 JavaScript 新关键词:let 和 const
这两个关键字在 JavaScript 中提供了 块作用域(Block Scope)变量(和常量)
在ES2015 之前,JavaScript 只有两种类型的作用域: 全局作用域和函数作用域
全局作用域
全局(在函数之外)声明的变量拥有全局作用域
全局变量在JavaScript 程序中的任何位置访问。
var carName = "porsche";
// 此处的代码可以使用 carName
function myFunction(){
// 此处的代码也可以使用 carName
}
如果在块外声明,那么var 和let 也很相似
它们都拥有全局作用域
var x = 10; //全局作用域
let y = 10; //全局作用域
函数作用域
局部(函数内)声明的变量拥有函数作用域
局部变量只能在他们被声明的函数内访问。
// 此处的代码不可以使用 carName
function myFunction(){
var carName = "porsche"
// code here CAN use carName
}
// 此处的代码不可以使用 carName
在函数内声明变量时,使用var和let很相似
它们都有函数作用域:
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
重新声明:
- 运行在程序的任何位置使用 var 重新声明 JavaScript 变量
- 在相同的作用域,或在相同的块中,通过 let 重新声明一个 var 变量是不允许的
- 在相同的作用域,或在相同的块中,通过 let 重新声明一个 let 变量是不允许的
- 在相同的作用域,或在相同的块中,通过 var 重新声明一个 let 变量是不允许的
- 在不同的作用域或块中,通过 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进行映射到不同区域(桶)进行保存。
插入过程:
- 得到key
- 通过hash函数得到hash值
- 得到桶号(一般都为hash值对桶数求模)
- 存放key和value在桶内(hashtable[nums[i]]=i)
取值过程:
- 得到key
- 通过hash函数得到hash值
- 得到桶号(一般都为hash值对桶数求模)
- 比较桶的内部元素是否与key相等,若都不相等,则没有找到。
- 取出相等的记录的value。(auto it = hashtable.find(target-nums[i]);if(it!=hashtable.end(){return it->second;//找到了}))