目录
Map的方法:
- clear:从映射中移除所有元素。
- delete:从映射中移除指定的元素。
- forEach:对映射中的每个元素执行指定操作。
- get:返回映射中的指定元素。
- has:如果映射包含指定元素,则返回 true。
- set:添加一个新建元素到映射。
- toString:返回映射的字符串表示形式。
- valueOf:返回指定对象的原始值。
- Object.getOwnPropertyNames(map).length:获取map的长度
- 遍历Map:
(1)keys():返回键名的遍历器。
(2)values():返回键值的遍历器。
(3)entries():返回所有成员的遍历器。
(4)forEach():遍历 Map 的所有成员。
let a = new Map([
['name','leo'],
['age',18]
])
for (let i of a.keys()){...};
for (let i of a.values()){...};
for (let i of a.entries()){...};
a.forEach((v,k,m)=>{
console.log(`key:${k},value:${v},map:${m}`)
})
Set的方法:
- 创建 Set
(1)new Set()方式创建:let v = new Set()
(2)通过传入数组方式创建:let v = new Set([1,2,3,3,5]) - add:添加元素
- delete:删除元素
- size:获取set中元素个数
- has: 判断 Set 中是否包含某个元素
- 遍历 Set
(1)forEach形式
let v = new Set()
v.add(1)
v.add(5)
v.forEach(t=>{
console.log(t)
})
(2)for of 形式
let v = new Set([1,2,3,3,5])
for(let t of v) {
console.log(t)
}
- Set转换成数组:使用 Array.from 方法
let v = new Set([1,2,3,3,5])
let a = Array.from(v)
1. 两数之和
给定一个整数数组 nums 和一个整数目标值 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]
解:
1.
2.
3.
4.
5.代码如下:
var twoSum = function(nums, target) {
let map = new Map();
for(let i = 0, len = nums.length; i < len; i++){
if(map.has(target - nums[i])){
return [map.get(target - nums[i]), i];
}else{
map.set(nums[i], i);
}
}
return [];
};
20. 有效的括号
给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
示例 1:
输入:s = “()”
输出:true
示例 2:
输入:s = “()[]{}”
输出:true
示例 3:
输入:s = “(]”
输出:false
示例 4:
输入:s = “([)]”
输出:false
示例 5:
输入:s = “{[]}”
输出:true
解:
1.用map来保存 ‘(’,’)’,’{’,’}’,’[’,’]’ 用以匹配
2.遍历s 遇到 ‘(’,’{’,’[’ 就存入数组 遇到 ’)’,’}’,’]’ 就弹出数组(取数组最后一个)来比较 若一样则为true 继续遍历 不一样则返回false
3.最后遍历完了 若数组为空 代表所有的都匹配上了 才返回true
代码如下:
JAVA:
public boolean isValid1(String s) {
while (s.contains("{}") || s.contains("[]") || s.contains("()")){
s = s.replace("{}","");
s = s.replace("[]","");
s = s.replace("()","");
}
return s.isEmpty();
}
public boolean isValid2(String s) {
Stack<Character> stack = new Stack<>();
int len = s.length();
for (int i = 0; i < len; i++) {
char c = s.charAt(i);
if (c == '(' || c == '{' || c == '['){
stack.push(c);
}else{
if (stack.isEmpty()) return false;
char left = stack.pop();
if (left == '(' && c != ')') return false;
if (left == '{' && c != '}') return false;
if (left == '[' && c != ']') return false;
}
}
return stack.isEmpty();
}
private static HashMap<Character,Character> map = new HashMap<>();
static {//key==value
map.put('(',')');
map.put('[',']');
map.put('{','}');
}
public boolean isValid3(String s) {
Stack<Character> stack = new Stack<>();
int len = s.length();
for (int i = 0; i < len; i++) {
char c = s.charAt(i);
if (map.containsKey(c)){//若c是map的key 即c是左括号
stack.push(c);
}else{//c是右括号
if (stack.isEmpty()) return false;
if (c != (map.get(stack.pop()))) return false;//stack.pop()是左括号 是key map.get(left) 根据key获取map中的值
// 根据左括号获取对应的右括号 右括号不等于栈顶弹出来的左括号 则不配对
}
}
return stack.isEmpty();
}
JS:
var isValid = function(s) {
if (s.length % 2 !== 0) return false;
let stack = [];
let p;
let map = new Map();
map.set('(', ')');
map.set('[', ']');
map.set('{', '}');
for (let i = 0; i < s.length; i++) {
if (map.has(s[i])) {
stack.push(s[i]);
}else if (s[i] === ')' || s[i] === ']' || s[i] === '}') {
p = stack.pop();
if (s[i] !== map.get(p)){
return false;
}
}else {
return false;
}
}
return stack.length === 0;
};
149. 直线上最多的点数
给定一个二维平面,平面上有 n 个点,求最多有多少个点在同一条直线上。
示例1:
输入: [[1,1],[2,2],[3,3]]
输出: 3
示例 2:
输入: [[1,1],[3,2],[5,3],[4,1],[2,3],[1,4]]
输出: 4
解:
1.使用枚举 只计算当前点i与当前点之后的点j的斜率
2.为每一个当前点i设置一个map map中的键是:i与j的斜率k(斜率计算公式:k = (y1 - y2) / (x1 - x2)) 值是k出现的次数
3.注意分母为0的情况 此时直线为x = b 在map中存入的键是最大值的对象用于区分 对于直线y = b 此时k = 0 map中存入键为0的对象用以区分
4.j遍历完了 该遍历下一个i了 又会新建一个map 所以j遍历结束后要遍历当前map 将最大的value 也就是k出现的次数存入res变量 最后输出res
5.以示例1为例 [1,1]的map的键为1 值为3 [2,2]的map的键为1 值为2 [3,3]的map的键为1 值为1 最后输出3 如果只用一个map的话 会输出4 会产生冗余 所以一定要给每一个点设置一个map
6.JS中最大的数字:Number.MAX_VALUE 最小的值:Number.MIN_VALUE
代码如下:
var maxPoints = function(points) {
if (points.length <= 2) return points.length;
let res = 2;
let k;
let num;
let x;
let y;
for (let i = 0; i < points.length - 1; i++) {
let map = new Map();
for (let j = i + 1; j < points.length; j++) {
x = points[i][0] - points[j][0];
y = points[i][1] - points[j][1];
k = x === 0 ? Number.MAX_VALUE : y / x;
if (map.has(k)) {
num = map.get(k) + 1;
map.set(k, num);
}else {
map.set(k, 2);
}
}
map.forEach((value,key) => {
res = Math.max(res,value);
})
}
return res;
};
146. LRU 缓存机制
运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制 。
实现 LRUCache 类:
- LRUCache(int capacity) 以正整数作为容量 capacity 初始化 LRU 缓存
- int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
- void put(int key, int value) 如果关键字已经存在,则变更其数据值;如果关键字不存在,则插入该组「关键字-值」。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。
LRU:是Least Recently Used的缩写,即最近最少使用,是一种常用的页面置换算法,选择最近最久未使用的页面予以淘汰。该算法赋予每个页面一个访问字段,用来记录一个页面自上次被访问以来所经历的时间 t,当须淘汰一个页面时,选择现有页面中其 t 值最大的,即最近最少使用的页面予以淘汰。
解:
/**
* @param {number} capacity
*/
var LRUCache = function(capacity) {
this.map = new Map();
this.capacity = capacity;
};
/**
* @param {number} key
* @return {number}
*/
LRUCache.prototype.get = function(key) {
if (this.map.has(key)) {
let v = this.map.get(key);
this.map.delete(key);
this.map.set(key,v);
return v;
}
else return -1;
};
/**
* @param {number} key
* @param {number} value
* @return {void}
*/
LRUCache.prototype.put = function(key, value) {
if (this.map.has(key)) {
this.map.delete(key);
this.map.set(key,value);
return;
}
if (this.map.size === this.capacity) {
this.map.delete(this.map.keys().next().value);
}
this.map.set(key,value);
};
剑指 Offer 09. 用两个栈实现队列
用两个栈实现一个队列。队列的声明如下,请实现它的两个函数 appendTail 和 deleteHead ,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,deleteHead 操作返回 -1 )
解:首先,两个栈分工不同,一个为入队栈,一个为出队栈,各自负责入队和出队。入队操作,直接压入入队栈即可,出队操作需要优先检查出队栈是否有数据,若无,需要从入队栈倒入后再操作。
代码如下:
var CQueue = function() {
this.stackA = [];
this.stackB = [];
};
CQueue.prototype.appendTail = function(value) {
this.stackA.push(value);
};
CQueue.prototype.deleteHead = function() {
if(this.stackB.length){
return this.stackB.pop();
}else{
while(this.stackA.length){
this.stackB.push(this.stackA.pop());
}
if(!this.stackB.length){
return -1;
}else{
return this.stackB.pop();
}
}
};
剑指 Offer 30. 包含min函数的栈
定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数,调用 min、push 及 pop 的时间复杂度都是 O(1)。
示例:
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.min(); --> 返回 -3.
minStack.pop();
minStack.top(); --> 返回 0.
minStack.min(); --> 返回 -2.
解:根据题意,我们需要在常量级的时间内找到最小值!这说明,我们绝不能在需要最小值的时候,再做排序,查找等操作来获取!所以,我们可以创建两个栈,一个栈是主栈 stack,另一个是辅助栈 minStack,用于存放对应主栈不同时期的最小值。
因为-2<0 所以minStack中存入-2
因为-3<-2 所以minStack中存入-3
代码如下:
JS:
var MinStack = function() {
this.x_stack = [];
this.min_stack = [Infinity];
};
MinStack.prototype.push = function(x) {
this.x_stack.push(x);
this.min_stack.push(Math.min(this.min_stack[this.min_stack.length - 1], x));
};
MinStack.prototype.pop = function() {
this.x_stack.pop();
this.min_stack.pop();
};
MinStack.prototype.top = function() {
return this.x_stack[this.x_stack.length - 1];
};
MinStack.prototype.min = function() {
return this.min_stack[this.min_stack.length - 1];
};
剑指 Offer 31. 栈的压入、弹出序列
输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。
示例 1:
输入:pushed = [1,2,3,4,5], popped = [4,5,3,2,1]
输出:true
解释:我们可以按以下顺序执行:
push(1), push(2), push(3), push(4), pop() -> 4,
push(5), pop() -> 5, pop() -> 3, pop() -> 2, pop() -> 1
示例 2:
输入:pushed = [1,2,3,4,5], popped = [4,3,5,1,2]
输出:false
解释:1 不能在 2 之前弹出。
解:
剑指 Offer 50. 第一个只出现一次的字符
在字符串 s 中找出第一个只出现一次的字符。如果没有,返回一个单空格。 s 只包含小写字母。
示例:1
s = “abaccdeff”
返回 “b”
示例 2
s = “”
返回 " "
解:
遍历字符串 将字符及字符出现的次数存入map 遍历map 返回值为1的键 若没有 则返回" "
map遍历:
for (const [key, val] of map) { if (val === 1) { return key; } }
代码如下:
JS:
var firstUniqChar = function(s) {
if (!s) return " ";
let map = new Map();
let char;
for (let i = 0; i < s.length; i++) {
let v = 1;
char = s.charAt(i);
if (map.has(char)){
v = map.get(char) + 1;
}
map.set(char, v);
}
for (const [key, val] of map) {
if (val === 1) {
return key;
}
}
return " "
};
剑指 Offer 50. 第一个只出现一次的字符
在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1(需要区分大小写).(从0开始计数)
解:遍历字符串 将字符及字符出现的次数保存在count数组(保存在map也行)遍历数组 去count中查找字符 若该字符对应的值为1 则返回索引
代码如下:
JAVA:
public class Solution {
public int FirstNotRepeatingChar(String str) {
if(str==null || str.length() == 0)return -1;
int[] count = new int[256];
//用一个类似hash的东西来存储字符出现的次数,很方便
for(int i=0; i < str.length();i++) {
count[str.charAt(i)]++;
}
for(int i=0; i < str.length();i++) {
if(count[str.charAt(i)]==1)
return i;
}
return -1;
}
}
JS:长见识了 竟然可以通过map[]来取值
function FirstNotRepeatingChar(str){
const map = new Map()
for(let i of str){
map[i] = (map[i]||0) +1
}
for(let i in str){
if(map[str[i]] == 1) return i
}
return -1
}
剑指 Offer 03. 数组中重复的数字
在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
示例 1:
输入:[2, 3, 1, 0, 2, 5, 3]
输出:2 或 3
解:
方法一:用set 遍历数组 若set中存在该元素说明该元素重复 直接返回该元素 若不存在 则加入set
代码如下:
JS:
var findRepeatNumber = function(nums) {
let set = new Set();
let num;
for (let i = 0; i < nums.length; i++) {
num = nums[i];
if (set.has(num)) {
return num;
}else {
set.add(num);
}
}
return -1;
};
(优化)方法二:原地交换 在一个长度为n的数组nums里 所有数字都在0~n-1的范围内 所以索引和数字应该一一对应 我们可以遍历数组 若元素大小===索引大小 直接跳过 不操作 若不相等 将元素放在对应索引处 在放之前判断一下该索引下的元素大小是否等于索引大小 若不相等直接放置 若相等 代表该元素重复 返回该元素
代码如下:
JAVA:
class Solution {
public int findRepeatNumber(int[] nums) {
int i = 0;
while(i < nums.length) {
if(nums[i] == i) {
i++;
continue;
}
if(nums[nums[i]] == nums[i]) return nums[i];
int tmp = nums[i];
nums[i] = nums[tmp];
nums[tmp] = tmp;
}
return -1;
}
}