for 循环相比,while 循环是一种更强大循环方式。当我们在使用 for 循环时,通常我们会提前知道循环的次数、以及循环的结束条件。

当场景满足以下条件时,我们通常会优先考虑使用 while 循环:

  • 1、循环次数不确定
  • 2、循环结束条件更复杂

1、平替 for 循环

例如,我们需要找到一个数组中,最大的那个值,我们可以使用 for 循环来实现:

1
function max(arr: number[]): number {
2
// 首先定义一个临时变量,用来存储最大值
3
let max = arr[0];
4
// 然后定义一个索引指针,从 1 开始,因为我们已经把第一个元素赋值给了 max,递增移动到数组最后一位
5
for (let i = 1; i < arr.length; i++) {
6
// 然后在索引指针移动的过程中,不断的比较当前元素和最大值,如果当前元素大于最大值,则替换
7
if (arr[i] > max) {
8
max = arr[i];
9
}
10
}
11
return max;
12
}

我们使用 while 循环来实现:

1
function max(arr: number[]): number {
2
// 首先定义一个临时变量,用来存储最大值
3
let max = arr[0];
4
// 然后定义一个索引指针
5
let i = 1;
6
// 当满足条件时,进入循环体,否则退出循环
7
while (i < arr.length) {
8
if (arr[i] > max) {
9
max = arr[i];
10
}
11
// while 循环通常在循环体的最结尾,编写循环迭代的方式
12
i++;
13
}
14
return max;
15
}

可以看到,while 循环会把初始化定义在循环的外面,然后关注循环结束条件,最后在循环体的结尾编写迭代方式。

由于我们可以把循环的迭代条件放到循环体内部来实现,所以,while 循环通常可以应对更复杂的情况。

2、双指针案例

接下来,我们来看一个稍微复杂一点的案例

已知一个已经排好序的数组,从该数组中,找到两个数之和等于目标值

由于要找到两个数,所以我们可以使用双指针来解决这个问题,一个指针指向数组的第一个元素,另一个指针指向数组的最后一个元素。

双指针分别从数组的两端往中间移动,每移动一次算出两数和,直到找到两个数之和等于目标值

1
// 在已排序数组中找出两数之和等于目标值
2
function twoSumSorted(arr, target) {
3
// 定义两个指针
4
let left = 0;
5
let right = arr.length - 1;
6
7
// 定义循环结束条件
8
while (left < right) {
9
const sum = arr[left] + arr[right];
10
if (sum === target) {
11
// 找到目标值,结束函数执行
12
return [left, right];
13
}
14
// 定义迭代条件
15
if (sum < target) {
16
left++;
17
} else {
18
right--;
19
}
20
}
21
return [];
22
}

注意这里的迭代条件,由于数组是已经排好序的,因此两数之和的变化趋势是:

  • 左指针向右移动,两数之和会变大
  • 右指针向左移动,两数之和会变小

当两数之和小于目标值时,我们需要让两数之和变大,此时移动左指针 当两数之和大于目标值时,我们需要让两数之和变小,此时移动右指针

如果题目中是无序的数组,我们可以先对数组进行排序,然后再使用双指针来解决这个问题

当然,我们也可以使用 for 循环来实现:

1
function twoSumSorted(arr, target) {
2
let left = 0;
3
let right = arr.length - 1;
4
5
for (; left < right;) {
6
const sum = arr[left] + arr[right];
7
if (sum === target) {
8
return [left, right];
9
}
10
if (sum < target) {
11
left++;
12
} else {
13
right--;
14
}
15
}
16
return [];
17
}

思考题

从一组正整数数组中,找出和为 k 的连续子数组的最大长度

解题思路:和为 k 的最长连续子数组
专栏首页
到顶
专栏目录