「这是我参与2022首次更文挑战的第21天,活动详情查看:2022首次更文挑战」
给你一个数组 seats 表示一排座位,其中 seats[i] = 1 代表有人坐在第 i 个座位上,seats[i] = 0 代表座位 i 上是空的(下标从 0 开始)。至少有一个空座位,且至少有一人已经坐在座位上。亚历克斯希望坐在一个能够使他与离他最近的人之间的距离达到最大化的座位上。返回他到离他最近的人的最大距离。
先理解一下题目的意思,假设输入为[1,0,0,0,1,0,1],首先位置0已经有人坐了,所以亚历克斯首先可以选择坐在位置1,此时亚历克斯离他最近的人为左边位置0的人,距离为1;亚历克斯也可以选择坐在位置2,此时亚历克斯离他最近的人为左边位置0的人和右边位置4的人,距离均为2;亚历克斯还可以选择坐在位置3,此时亚历克斯离他最近的人为右边位置4的人,距离为1;亚历克斯最后可以选择坐在位置6,此时亚历克斯离他最近的人为右边位置7的人,距离为1;由此可得,当亚历克斯坐在位置2,此时亚历克斯离他最近的人的距离最大,距离为2。
解法一
既然需要找出亚历克斯离他最近的人的最大距离,那么我们可以列出所有的可能,得到亚历克斯坐的每种位置的情况下距离他最近的人的距离,然后可得最大距离。
以上图为例,当亚历克斯坐在位置3时,我们需要分别找出左边和右边距离亚历克斯最近的人的距离,首先是左边,可以从亚历克斯的左边一个位置开始,也就是位置2,向左找第一个坐着的人,找到就得到距离,若未找到,标记一个-1,代码如下:
/* 假设i为亚历克斯当前的位置 */
// 找到左边离他最近的人
for (j = i - 1; j >= 0; --j) {
// 距离加1
++x;
if (seats[j] == 1) {
// 找到坐着的人,退出
break;
}
}
那么右边也是如此,从亚历克斯的右边一个位置开始,也就是位置3,向右找第一个坐着的人,找到就得到距离,若未找到,标记一个-1,代码如下:
// 找到右边离他最近的人
for (k = i + 1; k < seats.length; ++k) {
// 距离加1
++y;
if (seats[k] == 1) {
// 找到坐着的人,退出
break;
}
}
if (k == seats.length) {
// 若循环结束仍未找到,标记-1
y = -1;
}
这样左边和右边离亚历克斯最近的人的距离就都知道了,此时只需比较两个距离,取一个较小值,即可得到距离亚历克斯最近的人:
// 取较小值即为离他最近的人呢
if (x < y) {
list.add(x);
} else {
list.add(y);
}
不过需要考虑极端情况,倘若亚历克斯的左边或者右边没有人,那么就会出现左边或者右边的距离为-1,此时-1肯定是最小的,这样就影响了最后的结果,所以需要对该极端情况进行特殊处理:
// 处理极端情况
if (x == -1) {
list.add(y);
} else if (y == -1) {
list.add(x);
}
这样就得到了亚历克斯在位置3时离他最近的人的距离,此时只需循环得到亚历克斯在所有位置上的距离,代码如下:
List<Integer> list = new ArrayList<>();
for (int i = 0; i < seats.length; i++) {
if (seats[i] == 0) {
// 空座位才能入座
int x = 0;
int y = 0;
int j, k;
// 找到左边离他最近的人
for (j = i - 1; j >= 0; --j) {
// 距离加1
++x;
if (seats[j] == 1) {
// 找到坐着的人,退出
break;
}
}
if (j < 0) {
// 若循环结束仍未找到,标记-1
x = -1;
}
// 找到右边离他最近的人
for (k = i + 1; k < seats.length; ++k) {
// 距离加1
++y;
if (seats[k] == 1) {
// 找到坐着的人,退出
break;
}
}
if (k == seats.length) {
// 若循环结束仍未找到,标记-1
y = -1;
}
// 处理极端情况
if (x == -1) {
list.add(y);
continue;
} else if (y == -1) {
list.add(x);
continue;
}
// 取较小值即为离他最近的人呢
if (x < y) {
list.add(x);
} else {
list.add(y);
}
}
}
结果如下:
[1, 2, 1, 1]
最大距离即为集合中的最大值,最终代码如下:
public int maxDistToClosest(int[] seats) {
List<Integer> list = new ArrayList<>();
for (int i = 0; i < seats.length; i++) {
if (seats[i] == 0) {
// 空座位才能入座
int x = 0;
int y = 0;
int j, k;
// 找到左边离他最近的人
for (j = i - 1; j >= 0; --j) {
// 距离加1
++x;
if (seats[j] == 1) {
// 找到坐着的人,退出
break;
}
}
if (j < 0) {
// 若循环结束仍未找到,标记-1
x = -1;
}
// 找到右边离他最近的人
for (k = i + 1; k < seats.length; ++k) {
// 距离加1
++y;
if (seats[k] == 1) {
// 找到坐着的人,退出
break;
}
}
if (k == seats.length) {
// 若循环结束仍未找到,标记-1
y = -1;
}
// 处理极端情况
if (x == -1) {
list.add(y);
continue;
} else if (y == -1) {
list.add(x);
continue;
}
// 取较小值即为离他最近的人呢
if (x < y) {
list.add(x);
} else {
list.add(y);
}
}
}
System.out.println(list);
return list.stream().max(Integer::compareTo).get();
}
提交记录:
解法二
解法二的思路仍然是求出亚历克斯在每个位置上离他最近的人的距离,然后得到最大距离,不过,在求距离的过程中,我们可以优化一下解法一的代码。
还是以上图为例,首先我们初始化两个数组分别用来记录左边和右边离亚历克斯最近的人的距离:
int N = seats.length;
int[] left = new int[N], right = new int[N];
Arrays.fill(left, N);
Arrays.fill(right, N);
先找出所有位置情况下左边离亚历克斯最近的人的距离,也就是先求出数组left,首先位置0有人无法入座,所以将left[0]赋值为0,而位置1没人可以入座,其距离应该等于前一个元素值加1,即:left[i - 1] + 1,此时left数组的值如下:
[0,1,7,7,7,7,7]
当入座位置2时,left[i - 1] + 1 = 1 + 1 = 2,left数组值如下:
[0,1,2,7,7,7,7]
当入座位置3时,left[i - 1] + 1 = 2 + 1 = 3,left数组值如下:
[0,1,2,3,7,7,7]
位置4有人无法入座,所以赋值为1,left数组值如下:
[0,1,2,3,1,7,7]
以此类推,最终得到left数组:
[0,1,2,3,0,1,0]
代码如下:
for (int i = 0; i < N; ++i) {
if (seats[i] == 1) left[i] = 0;
else if (i > 0) left[i] = left[i - 1] + 1;
}
这样就求得了左边的每种情况。 接着以同样的方式求得右边,从后往前遍历,位置7有人坐,赋值为0:
[7,7,7,7,7,7,0]
当入座位置6时,right[i] = right[i + 1] + 1 = 0 + 1 = 1,right数组值为:
[7,7,7,7,7,1,0]
以此类推,得到right数组:
[0,3,2,1,0,1,0]
代码如下:
for (int i = N - 1; i >= 0; --i) {
if (seats[i] == 1) right[i] = 0;
else if (i < N - 1) right[i] = right[i + 1] + 1;
}
得到了所有结果后,只需找出最大距离即可:
int ans = 0;
for (int i = 0; i < N; ++i)
if (seats[i] == 0)
ans = Math.max(ans, Math.min(left[i], right[i]));
return ans;
最终代码如下:
public int maxDistToClosest(int[] seats) {
int N = seats.length;
int[] left = new int[N], right = new int[N];
Arrays.fill(left, N);
Arrays.fill(right, N);
for (int i = 0; i < N; ++i) {
if (seats[i] == 1) left[i] = 0;
else if (i > 0) left[i] = left[i - 1] + 1;
}
for (int i = N - 1; i >= 0; --i) {
if (seats[i] == 1) right[i] = 0;
else if (i < N - 1) right[i] = right[i + 1] + 1;
}
int ans = 0;
for (int i = 0; i < N; ++i)
if (seats[i] == 0)
ans = Math.max(ans, Math.min(left[i], right[i]));
return ans;
}
提交记录: