文章目录
📈「作者简介」:不知名十八线技术博主
📚「推荐主页」:阿珊和她的猫
🕐「简历必备」前后端实战项目(推荐:⭐️⭐️⭐️⭐️⭐️)
知识储备
JavaScript有没有指针的概念
在 JavaScript 中,没有明确的指针概念。相对于其他低级编程语言(如 C 或 C++),JavaScript 中的变量赋值和传递是基于值的,而不是基于指针的。这意味着在 JavaScript 中,变量直接存储数据值,而不是指向内存中的位置。
虽然 JavaScript 中没有指针的概念,但是它提供了引用类型(对象、数组等)的引用。引用类型的值在赋值和传递过程中,并不会创建副本,而是通过引用来访问和操作原始数据。
例如,当你将一个数组赋值给另一个变量时,它们指向内存中同一个实际数组,而不是创建数组的副本。修改其中一个变量所引用的数组,会影响到另一个变量。这是因为它们共享同一个引用,即指向相同的内存地址。
let arr1 = [1, 2, 3];
let arr2 = arr1;
arr2.push(4); // 修改 arr2 也会影响到 arr1
console.log(arr1); // 输出 [1, 2, 3, 4]
console.log(arr2); // 输出 [1, 2, 3, 4]
注意,这里的引用并不是指针,而是指向实际对象的值的引用。JavaScript 引擎隐藏了底层的指针细节,提供了更高级的抽象,使得开发者无需关心内存管理。
数组基础知识
数组定义与初始化
在JavaScript中,数组的定义和初始化可以使用以下语法:
// 定义并初始化一个整型数组
let arr = [1, 2, 3, 4, 5];
// 仅定义数组,不进行初始化
let arr = [];
// 初始化部分元素,其他元素默认为undefined
let arr = [1, 2];
// 定义字符串数组并初始化
let strArr = ['Hello', 'World'];
// 定义混合类型的数组
let mixedArr = [1, 'apple', true];
// 使用Array构造函数定义并初始化数组
let arr = new Array(1, 2, 3, 4, 5);
// 使用Array构造函数定义指定长度的数组
let arr = new Array(5); // 创建一个长度为5的数组,元素都为undefined
在JavaScript中,数组是动态的,可以随时添加或删除元素,因此可以根据需要灵活调整数组的大小和内容。可以通过索引访问数组元素,并使用数组的内置方法和属性来进行各种操作。
数组访问
介绍使用下标对数组元素进行读取和修改。
在JavaScript中,可以使用下标(索引)来访问/读取数组元素和修改数组元素的值。数组的下标从0开始,依次递增。
下面是一些示例代码展示如何使用下标对数组元素进行读取和修改:
let arr = [1, 2, 3, 4, 5];
// 读取数组元素
console.log(arr[0]); // 输出:1
console.log(arr[2]); // 输出:3
// 修改数组元素的值
arr[0] = 10;
console.log(arr); // 输出:[10, 2, 3, 4, 5]
arr[2] = 30;
console.log(arr); // 输出:[10, 2, 30, 4, 5]
通过使用方括号([])加上索引,可以访问和修改指定位置的数组元素。注意,使用存在的索引进行读取/修改,会得到相应位置的元素值;而使用不存在的索引进行读取/修改,会得到undefined。
另外,需要注意的是,如果在使用访问或修改数组元素时,使用了超出数组范围的索引,会导致错误。因此,在对数组进行操作时,应确保索引值在正确的范围内以避免错误发生。
此外,还可以使用数组的length属性来获取数组的长度,以便在循环中遍历数组的元素。
let arr = [1, 2, 3, 4, 5];
for (let i = 0; i < arr.length; i++) {
console.log(arr[i]);
}
// 输出:
// 1
// 2
// 3
// 4
// 5
使用上述方法,可以方便地读取和修改数组中的元素,并在操作过程中利用数组的索引来处理不同位置的元素。
数组操作
常见的数组操作,如添加、删除、修改元素等。
在JavaScript中,有许多常见的数组操作可以用来添加、删除和修改数组元素。下面是一些常用的数组操作方法示例:
-
添加元素:
- 使用push()方法向数组末尾添加一个或多个元素。
let arr = [1, 2, 3]; arr.push(4); console.log(arr); // 输出:[1, 2, 3, 4]
- 使用unshift()方法向数组开头添加一个或多个元素。
let arr = [2, 3]; arr.unshift(1); console.log(arr); // 输出:[1, 2, 3]
- 使用push()方法向数组末尾添加一个或多个元素。
-
删除元素:
- 使用pop()方法删除数组末尾的元素,并返回被删除的元素。
let arr = [1, 2, 3, 4]; let removedElement = arr.pop(); console.log(removedElement); // 输出:4 console.log(arr); // 输出:[1, 2, 3]
- 使用shift()方法删除数组开头的元素,并返回被删除的元素。
let arr = [1, 2, 3]; let removedElement = arr.shift(); console.log(removedElement); // 输出:1 console.log(arr); // 输出:[2, 3]
- 使用pop()方法删除数组末尾的元素,并返回被删除的元素。
-
修改元素:
- 直接通过索引对数组元素进行赋值修改。
let arr = [1, 2, 3]; arr[1] = 10; console.log(arr); // 输出:[1, 10, 3]
- 直接通过索引对数组元素进行赋值修改。
-
替换元素:
- 使用splice()方法替换数组中的元素。
let arr = [1, 2, 3, 4, 5]; arr.splice(2, 1, 'a', 'b'); console.log(arr); // 输出:[1, 2, 'a', 'b', 4, 5]
- 使用splice()方法替换数组中的元素。
-
拷贝数组:
- 使用slice()方法创建一个原数组的浅拷贝。
let arr = [1, 2, 3]; let newArr = arr.slice(); console.log(newArr); // 输出:[1, 2, 3]
- 使用slice()方法创建一个原数组的浅拷贝。
上述方法仅是数组操作的一小部分,JavaScript还提供了更多的数组方法和技巧,用于对数组进行过滤、排序、搜索等操作。通过熟练掌握这些方法,可以高效处理和操作数组数据。
双指针概述
什么是双指针
解释双指针的概念和作用。
在计算机科学中,双指针是一种常见的技术,用于解决一些特定问题。
双指针指的是使用两个指针在数组或链表中同时遍历或比较元素的方法。
双指针通常有以下两种使用方式和应用场景:
1. 对撞指针(Two Pointers Approach)
- 使用两个指针从数组的两端向中间移动,直到两个指针相遇或交错。
- 这种技术常用于已排序数组的查找或比较。例如,在有序数组中查找目标元素、寻找两数之和等问题。
- 由于数组已排序,使用对撞指针可以利用数组的有序性来提高查找效率。
2. 快慢指针(Fast and Slow Pointers)
- 使用两个指针以不同的速度遍历链表或数组。
- 这种技术常用于解决与链表或数组中的环相关的问题,如判断链表是否有环、找到链表的中点、寻找链表中的环的起点等。
- 快指针每次移动两步,慢指针每次移动一步,它们可以在O(n)的时间内相遇,从而判断是否存在环,并找到环的起点。
双指针技术的优点是能够以较低的时间和空间复杂度解决一些问题。通过同时遍历或比较两个指针,可以简化算法的实现逻辑并提高效率。
需要注意的是,双指针并非适用于所有问题,只有在问题的特定要求下才能使用双指针技巧。因此,在解决问题时,需要根据具体情况确定是否适用双指针方法,并根据问题特点合理选择和操作指针。
双指针的应用场景
列举常见问题,如数组遍历、查找、反转、排序等。
双指针技术在JavaScript中有许多常见的应用场景,包括数组遍历、查找、反转、排序等。以下是一些常见问题和对应的双指针解决方案:
-
数组遍历:
- 使用两个指针来遍历数组,一个指针负责迭代数组的索引,另一个指针用于访问或处理当前索引处的元素。
- 示例:计算数组中的平均值、找到数组中的最大/最小值等。
-
有序数组的查找:
- 使用对撞指针在有序数组中查找目标元素。
- 示例:在有序数组中查找特定值,例如使用二分查找。
-
反转字符串/数组:
- 使用对撞指针交换数组或字符串中对应位置的元素。
- 示例:反转数组或字符串,例如将字符串 “hello” 反转为 “olleh”。
-
验证回文字符串/数组:
- 使用对撞指针比较数组或字符串的对称元素。
- 示例:确定给定字符串或数组是否是回文,例如判断字符串 “racecar” 是否是回文。
-
删除数组中的重复元素:
- 使用快慢指针在数组中移动,快指针用于遍历数组并查找重复元素,慢指针指向新数组的下一个空槽。
- 示例:从已排序的数组中删除重复的元素,使每个元素只出现一次。
-
归并两个有序数组:
- 使用对撞指针和一个额外的临时数组,遍历两个有序数组并按顺序合并它们的元素。
- 示例:将两个有序数组合并为一个有序数组。
这只是一些常见的双指针应用场景示例,实际上双指针在解决各种数组相关问题时都可能发挥作用。具体应用场景还取决于问题的特定要求和约束。
实例分析
问题一:反转数组
使用双指针方法实现数组反转。
可以使用双指针方法实现数组反转。以下是使用JavaScript编写的反转数组的双指针示例:
function reverseArray(arr) {
let left = 0;
let right = arr.length - 1;
while (left < right) {
// 交换左右指针所指向的元素
let temp = arr[left];
arr[left] = arr[right];
arr[right] = temp;
// 移动指针继续比较下一对元素
left++;
right--;
}
return arr;
}
// 示例用法
let nums = [1, 2, 3, 4, 5];
console.log(reverseArray(nums)); // 输出:[5, 4, 3, 2, 1]
上述代码中,我们使用双指针方法来实现数组的反转。开始时,左指针left
指向数组的第一个元素,右指针right
指向数组的最后一个元素。在每一轮循环中,我们交换左右指针所指向的元素值,然后向中间移动指针,继续比较下一对元素,直到两个指针相遇或交错。
通过这种方式,我们可以快速地反转数组中的元素顺序,将数组的第一个元素与最后一个元素交换,第二个与倒数第二个交换,以此类推,最终实现数组的反转。
在示例中,我们将数组[1, 2, 3, 4, 5]
传递给reverseArray
函数,并打印出反转后的数组[5, 4, 3, 2, 1]
。
问题二:求两数之和
使用对撞指针方法求有序数组中两数之和的索引。
使用对撞指针方法可以在有序数组中找到两数之和等于给定目标值的索引。以下是使用JavaScript编写的对撞指针求解两数之和的索引示例:
function twoSum(nums, target) {
let left = 0;
let right = nums.length - 1;
while (left < right) {
let sum = nums[left] + nums[right];
if (sum === target) {
return [left, right]; // 返回两个数的索引
} else if (sum < target) {
left++; // 和比目标值小,左指针右移
} else {
right--; // 和比目标值大,右指针左移
}
}
return []; // 未找到匹配的两数之和
}
// 示例用法
let nums = [-2, 0, 3, 5, 7, 9];
let target = 8;
console.log(twoSum(nums, target)); // 输出:[2, 4],表示 nums[2] + nums[4] = 8
上述代码中,我们定义了twoSum
函数,接收一个有序数组nums
和目标值target
作为参数。开始时,左指针left
指向数组的第一个元素,右指针right
指向数组的最后一个元素。在每一轮循环中,我们计算左右指针所指向的两个元素的和,并与目标值进行比较。
- 如果和等于目标值
target
,则返回两个数的索引。 - 如果和小于目标值
target
,说明左指针所指向的数太小,我们将左指针右移。 - 如果和大于目标值
target
,说明右指针所指向的数太大,我们将右指针左移。
通过不断移动指针,直到找到和等于目标值或指针相遇,我们可以在O(n)时间复杂度内找到解。
在示例中,我们将有序数组[-2, 0, 3, 5, 7, 9]
和目标值8
传递给twoSum
函数,并打印出两数之和等于目标值的索引[2, 4]
,表示nums[2] + nums[4] = 8
。
问题三:移除重复元素
使用快慢指针方法移除有序数组中的重复元素。
使用快慢指针方法可以移除有序数组中的重复元素。
以下是使用JavaScript编写的快慢指针移除重复元素的示例:
function removeDuplicates(nums) {
if (nums.length === 0) {
return 0; // 数组为空,直接返回0
}
let slow = 0; // 慢指针,指向去重后的数组的最后一个元素索引
for (let fast = 1; fast < nums.length; fast++) {
if (nums[fast] !== nums[slow]) {
slow++; // 移动慢指针
nums[slow] = nums[fast]; // 将不重复的元素存储在慢指针当前位置
}
}
return slow + 1; // 返回去重后的数组长度
}
// 示例用法
let nums = [1, 1, 2, 3, 3, 4, 4, 4, 5];
console.log(removeDuplicates(nums)); // 输出:5,表示去重后的数组长度
console.log(nums.splice(0, removeDuplicates(nums))); // 输出:[1, 2, 3, 4, 5],表示去重后的数组内容
在上述代码中,我们定义了removeDuplicates
函数,接收一个有序数组nums
作为参数。开始时,我们定义一个慢指针slow
指向去重后的数组的最后一个元素的索引(初始为0)。之后,我们使用快指针fast
从数组的第二个元素开始遍历。
在每一轮循环中,如果快指针所指向的元素与慢指针所指向的元素不相等,则表示出现了不重复的元素。此时,我们将慢指针右移一步,并将不重复的元素存储在慢指针当前位置。通过这种方式,我们不断更新慢指针所指向的位置,实现了去除重复元素的操作。
最后,我们返回慢指针所在位置加1的值,即去重后的数组的长度。在示例中,我们将数组[1, 1, 2, 3, 3, 4, 4, 4, 5]
传递给removeDuplicates
函数,打印出去重后的数组长度为5,表示去重后的数组为[1, 2, 3, 4, 5]
。我们还通过使用splice
方法将原数组中的重复元素去除,打印出去重后的数组内容为[1, 2, 3, 4, 5]
。