数组


1920. 基于排列构建数组

考点:数组的遍历

在这里,我们得使用map函数,可以大量节省空间,而像c++单项遍历是不可取的

注意:这里不能返回nums数组,因为使用map本质也算是创建了一个新数组,故我们返回num数组

1
2
3
4
5
var buildArray = function(nums) {
return nums.map((num,index)=>(
nums[nums[index]]
))
};

1929.数组串联

考点:数组的拼接

在这里,我们要使用concat()来进行数组的拼接,节省时间和空间

不要过多的依赖push和pop

1
2
3
var getConcatenation = function(nums) {
return nums.concat(nums)
};

1828. 统计一个圆中点的数目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var isIn = function(point, query){
return (point[0] - query[0]) ** 2 + (point[1] - query[1]) ** 2 <= query[2] ** 2 ? 1 : 0
}

var countPointsWithOneCircle = function(points, circle){
var count = 0
for(var i = 0; i < points.length; i++){
if(isIn(points[i], circle))count++
}
return count
}

var countPoints = function(points, queries) {
var arr = new Array()
for(var i in queries){
arr.push(countPointsWithOneCircle(points, queries[i]))
}
return arr
};

1480. 一维数组的动态和

考点:动态规划

1
2
3
4
5
6
var runningSum = function(nums) {
for(var i = 1; i < nums.length; i++){
nums[i] += nums[i - 1]
}
return nums
};

1720. 解码异或后的数组

考点:动态规划、异或问题

1
2
3
4
5
// 回旋
a ^ b ^ b = a
若:a ^ b = c,则:
a = c ^ b
b = c ^ a
1
2
3
4
5
6
7
var decode = function(encoded, first) {
encoded.unshift(first)
for(var i = 1; i < encoded.length; i++){
encoded[i] ^= encoded[i - 1]
}
return encoded
};

1689.十-二进制数的最少数目

考点:…符号的使用,可以让字符串解构

1
2
3
4
5
6
7
8
9
var minPartitions = function(n) {
var max = 0
var num = parseInt(n)
while(num !== 0){
max = max > num % 10 ? max : (num % 10)
num = parseInt(num / 10)
}
return max
};

27.移除元素

考点:双指针法:当指到需要移除的元素时,慢指针停一格,然后用快指针的数据赋值给慢指针的数据

1
2
3
4
5
6
7
8
9
10
11
var removeElement = function(nums, val) {
// 慢指针
var k = 0

for(var i = 0; i < nums.length; i++){
if(nums[i] !== val){
nums[k++] = nums[i]
}
}
return k
};

977. 有序数组的平方

考点:双指针法,当指到的元素函数值较小时,就将函数值拿出来推进新数组,然后指针移动

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var sortedSquares = function(nums) {
var arr = new Array()
var i = 0
var j = nums.length - 1
while(i <= j){
if(nums[i] ** 2 <= nums[j] ** 2){
arr.unshift(nums[j] ** 2)
j--
}else{
arr.unshift(nums[i] ** 2)
i++
}
}
return arr
};

209. 长度最小的子数组

考点:双指针法,制造一个滑动窗口

有点类似于栈和队列

当滑动窗口满条件时,就往外出队列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var minSubArrayLen = function(target, nums) {
var fast = 0
var low = 0
var length = nums.length
var sum = 0
var res = length + 1
while(fast < length + 1){
sum += nums[fast]
fast++
while(sum >= target){
res = res < fast - low ? res : fast - low
sum -= nums[low]
low++
}
}

return res > length ? 0 : res
};

59. 螺旋矩阵 II

考点:边界条件的判断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
var generateMatrix = function(n) {
// 创建n * n二维数组
const res = Array.from({length: n}).map(()=>new Array(n))
var x = 0,
y = 0,
i = 0,
count = 1,
loop = n >> 1
while(loop >= ++i){
var X = x,
Y = y

while(X < n - i){
res[Y][X++] = count++
}
while(Y < n - i){
res[Y++][X] = count++
}
while(X > x){
res[Y][X--] = count++
}
while(Y > y){
res[Y--][X] = count++
}
y++
x++
console.log(123 & 1)
}
if(n & 1){
res[y][x] = count
}
return res
};

链表

203. 移除链表元素

考点:对于头节点的处理

方法:往往使用虚拟结点法,在头节点之前设置一个节点virtual,之后给出一个返回值virtual.next即可

1
2
3
4
5
6
7
8
9
10
11
12
var removeElements = function(head, val) {
var virtualHead = new ListNode(0, head)
var tmp = virtualHead
while(tmp.next){
if(tmp.next.val === val){
tmp.next = tmp.next.next
continue
}
tmp = tmp.next
}
return virtualHead.next
};

707. 设计链表

思路:我们需要在链表类里面有一个长度,这样书写链表的增删查改时比较容易

此外,善用虚拟头结点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
/**
* Initialize your data structure here.
*/
var MyLinkedList = function() {
this.head = null
this.length = 0
};

class node {
constructor(val, next){
this.val = val
this.next = next
}
}

/**
* Get the value of the index-th node in the linked list. If the index is invalid, return -1.
* @param {number} index
* @return {number}
*/
MyLinkedList.prototype.get = function(index) {
var temp = new node(0, this.head)
if(index < 0 || index >= this.length){
return -1
}
for(var i = 0; i < index; i++){
temp = temp.next
}
return temp.next.val
};

/**
* Add a node of value val before the first element of the linked list. After the insertion, the new node will be the first node of the linked list.
* @param {number} val
* @return {void}
*/
MyLinkedList.prototype.addAtHead = function(val) {
this.addAtIndex(0, val)
};

/**
* Append a node of value val to the last element of the linked list.
* @param {number} val
* @return {void}
*/
MyLinkedList.prototype.addAtTail = function(val) {
this.addAtIndex(this.length, val)
};

/**
* Add a node of value val before the index-th node in the linked list. If index equals to the length of linked list, the node will be appended to the end of linked list. If index is greater than the length, the node will not be inserted.
* @param {number} index
* @param {number} val
* @return {void}
*/
MyLinkedList.prototype.addAtIndex = function(index, val) {
if(index < 0){
return
}
var virtual = new node(0, this.head)
var temp = virtual
for(var i = 0; i < index && i < this.length; i++){
temp = temp.next
}
var insert = new node(val)
insert.next = temp.next
temp.next = insert
this.head = virtual.next
this.length++
};

/**
* Delete the index-th node in the linked list, if the index is valid.
* @param {number} index
* @return {void}
*/
MyLinkedList.prototype.deleteAtIndex = function(index) {
var virtualH = new node(0, this.head)
var temp = virtualH

if(index < 0 || this.length <= index){
return
}

for(var i = 0; i < index; i++){
if(!temp.next){
return
}
temp = temp.next
}
temp.next = temp.next.next
this.head = virtualH.next
this.length--
};

206. 反转链表

考点:双指针法,不过要着重理清楚链表的指向关系

1
2
3
4
5
6
7
8
9
10
11
12
var reverseList = function(head) {
var aft = null
var pre = head
while(pre){
var change = pre
pre = pre.next
change.next = aft

aft = change
}
return aft
};

19. 删除链表的倒数第 N 个结点

考点:因为特殊值的原因,最好设置虚拟节点

找倒数的第N个结点,又要一次遍历结束,我们就使用两个指针,相隔为N - 1就可以了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var removeNthFromEnd = function(head, n) {
var virtual = new ListNode(0, head)
var slow = fast = virtual
while(n--){
fast = fast.next
}
if(!fast){
return virtual.next
}
while(fast.next){
fast = fast.next
slow = slow.next
}
slow.next = slow.next.next
return virtual.next
};

哈希表


242. 有效的字母异位词

考点:构建26位的哈希表,用空间换取时间

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var isAnagram = function(s, t) {
if(s.length !== t.length){
return false
}
var arr = Array(26).fill(0)
const base = 'a'.charCodeAt()
for(var i of s){
arr[i.charCodeAt() - base]++
}
for(var i of t){
arr[i.charCodeAt() - base]--
if(arr[i.charCodeAt() - base] < 0){
return false
}
}
return true
};

1002. 查找常用字符

考点:也是构建哈希表,对每一个词语都构建一个26长度的哈希表,然后新数组是哈希表对应位置的最小值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
var commonChars = function(words) {
var base = 'a'.charCodeAt()
var arr = new Array(100)

for(var i in words){
arr[i] = new Array(26).fill(0)
var str2 = [...words[i]].join('')
for(var j in str2){
arr[i][str2[j].charCodeAt() - base]++
}
}

var res = new Array(26).fill(100)
for(var i in words){
for(var j = 0; j < 26; j++){
res[j] = res[j] < arr[i][j] ? res[j] : arr[i][j]
}
}
console.log(res)
console.log(String.fromCharCode(3 + base))
var outprint = new Array()
for(var i = 0; i < 26; i++){
if(res[i] === 0){
continue
}
while(res[i]--){
outprint.push(String.fromCharCode(i + base))
}
}
return outprint
};

349. 两个数组的交集

考点:set函数【可以用于数组去重】,并且该数据结构可以和数组之间相互转化

对一个数据进行去重,然后再逐项检查就好

1
2
3
4
5
6
7
8
// 相互转化
const setArr = new Set(arr)
arr = Array.from(setArr)

// 往结构里面添加x,会去重
setArr.add(x)
// 判断是否有这个元素x
setArr.has(x)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var intersection = function(nums1, nums2) {
if(nums1.length < nums2.length){
const temp = nums2
nums2 = nums1
nums1 = temp
}
var setNums1 = new Set(nums1)
var setNums2 = new Set()
for(var i = 0; i < nums2.length; i++){
if(setNums1.has(nums2[i])){
setNums2.add(nums2[i])
}
}
return Array.from(setNums2)
};

202. 快乐数

思路:不是快乐数的话,那么产生的步骤会有一个数值的loop,如果找到两次数值一样那么就不是快乐数

当然,在这里我们要熟练使用Set的判断是否在里面和添加数据这两个API

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var getSum = function(n) {
var sum = 0
while(n) {
sum += (n % 10) ** 2
n = parseInt(n / 10)
}
return sum
}
var isHappy = function(n) {
var set = new Set()
var nowData = getSum(n)
while(!set.has(nowData)){
set.add(nowData)
nowData = getSum(nowData)
if(nowData === 1){
return true
}
}
return false
};

1. 两数之和

思路:使用hash来拿出索引(下标)

同样的,hash也是需要推入索引下标的

典型的空间换时间

1
2
3
4
5
6
7
8
9
10
var twoSum = function (nums, target) {
let hash = {}
for(var i = 0; i < nums.length; i++){
if(hash[target - nums[i]] !== undefined){
return [i, hash[target - nums[i]]]
}
hash[nums[i]] = i
}
return []
};

454. 四数相加 II

思路:两两数组求和,再对和使用哈希表

Map的使用特别灵活,如果只是使用数组可能会出现两数之和为负数,这样根本无法定位

Map的使用:

1
2
3
4
5
6
// 使用
const myMap = new Map()
// 设置键值对,用于表示两者的映射关系
myMap.set(number1, number2)
// 获取对应的映射(number2)
myMap.get(number1)

题解:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var fourSumCount = function(nums1, nums2, nums3, nums4) {
const myMap = new Map()
let cnt = 0
for(const n1 of nums1){
for(const n2 of nums2){
myMap.set(n1 + n2, (myMap.get(n1 + n2) || 0) + 1)
}
}

for(const n3 of nums3){
for(const n4 of nums4){
cnt += myMap.get((0 - n3 - n4)) || 0
}
}
return cnt
};