找出数组排序后的目标下标 图解题解
这道题到底在问什么
- 输入
- nums=[1,2,5,2,3], target=2
- 输出
- [1,2] 排序后 [1,2,2,3,5],值 2 在下标 1 和 2
- 输入
- nums=[1,2,5,2,3], target=4
- 输出
- [] 数组里没有 4
最优解:一步一步想明白
- 3记住这套路:先排序让相等的值抱团,再扫一遍把等于 target 的下标一个个收进来。下面先看原始数组长什么样。
- 4这是原始的 nums,一共 8 个数,还没排序。我们要找的目标值是 3。你先扫一眼,3 在这里东一个西一个,毫无规律,直接在原数组上找下标是没有意义的,因为题目要的是排序之后的下标。
- 5把原数组里所有值为 3 的格子标成绿色,它们分别在下标 1、3、5。你看,它们是散开的,中间还夹着别的数。这正是为什么要先排序:排完之后,这三个 3 会被拢到一起。
- 6调用语言内置的排序,把 nums 从小到大排好,现在它是 [1,3,3,3,5,6,8,9]。注意看,三个 3 已经紧紧挨在一块了。接下来从下标 0 开始,一格一格往右扫,遇到等于 3 的就把下标收进答案。
- 7紫色指针走到下标 0,这里的值是 1。拿它和 target 也就是 3 比一比,看是小、是等还是大。
- 81 比 3 小,它排在目标块的左边,不是我们要的,标成蓝色跳过。继续往右走。
- 9紫色指针走到下标 1,这里的值是 3。拿它和 target 也就是 3 比一比,看是小、是等还是大。
- 10正好等于 3,命中!把下标 1 收进答案,这一格标成绿色。目前收集到 [1]。
- 11紫色指针走到下标 2,这里的值是 3。拿它和 target 也就是 3 比一比,看是小、是等还是大。
- 12正好等于 3,命中!把下标 2 收进答案,这一格标成绿色。目前收集到 [1,2]。
- 13紫色指针走到下标 3,这里的值是 3。拿它和 target 也就是 3 比一比,看是小、是等还是大。
- 14正好等于 3,命中!把下标 3 收进答案,这一格标成绿色。目前收集到 [1,2,3]。
- 15紫色指针走到下标 4,这里的值是 5。拿它和 target 也就是 3 比一比,看是小、是等还是大。
- 165 比 3 大了。因为已经排好序,它右边的数只会更大,再也不会碰到 3,这一格标灰。参考代码是老实扫完的,但你心里要清楚:到这里其实已经可以收工了。
- 17紫色指针走到下标 5,这里的值是 6。拿它和 target 也就是 3 比一比,看是小、是等还是大。
- 186 比 3 大了。因为已经排好序,它右边的数只会更大,再也不会碰到 3,这一格标灰。参考代码是老实扫完的,但你心里要清楚:到这里其实已经可以收工了。
- 19紫色指针走到下标 6,这里的值是 8。拿它和 target 也就是 3 比一比,看是小、是等还是大。
- 208 比 3 大了。因为已经排好序,它右边的数只会更大,再也不会碰到 3,这一格标灰。参考代码是老实扫完的,但你心里要清楚:到这里其实已经可以收工了。
- 21紫色指针走到下标 7,这里的值是 9。拿它和 target 也就是 3 比一比,看是小、是等还是大。
- 229 比 3 大了。因为已经排好序,它右边的数只会更大,再也不会碰到 3,这一格标灰。参考代码是老实扫完的,但你心里要清楚:到这里其实已经可以收工了。
- 23这里藏着一个更快的思路。比 3 小的元素只有 1 个,就是那个 1,所以排序后第一个 3 一定落在下标 1。目标块从下标 1 起头,一共 3 个 3,于是下标就是 1、2、3。顺着这个观察,其实连排序都能省掉,后面面试环节细说。
- 24扫完全程,绿色的三格就是等于 3 的位置,下标依次是 1、2、3。所以答案是 [1,2,3],和我们一开始说的对上了。左边蓝色的更小、右边灰色的更大,绿色这一块就是目标下标。
⚠️ 容易写错的地方
✗ 错:在原始数组上直接找下标就返回
✓ 对:必须先排序,再找排序后的下标
题目要的是排序后的下标,原数组里 3 在下标 1、3、5,和排序后的 1、2、3 完全不同
✗ 错:target 不存在时返回 [-1] 或抛错
✓ 对:返回空列表 []
题面明确规定不存在目标下标时返回空列表,不是特殊标记
✗ 错:以为重复的 target 只算一个下标
✓ 对:每一个等于 target 的下标都要收
有几个等于 target 的元素就有几个下标,例子里三个 3 对应三个下标
✗ 错:返回的下标顺序随意
✓ 对:按递增顺序返回
从左到右扫描天然递增,顺手就满足了这个要求
完整代码(Python / C++ / Java)
Python
from __future__ import annotations
from typing import *
from collections import *
from functools import *
from itertools import *
from math import *
from heapq import *
from bisect import *
class Solution:
def targetIndices(self, nums: List[int], target: int) -> List[int]:
nums.sort()
return [i for i, v in enumerate(nums) if v == target]C++
#include <algorithm>
#include <array>
#include <cctype>
#include <climits>
#include <cmath>
#include <deque>
#include <functional>
#include <iostream>
#include <limits>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <tuple>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
using namespace std;
class Solution {
public:
vector<int> targetIndices(vector<int>& nums, int target) {
sort(nums.begin(), nums.end());
vector<int> ans;
for (int i = 0; i < nums.size(); ++i) {
if (nums[i] == target) {
ans.push_back(i);
}
}
return ans;
}
};Java
import java.util.*;
class Solution {
public List<Integer> targetIndices(int[] nums, int target) {
Arrays.sort(nums);
List<Integer> ans = new ArrayList<>();
for (int i = 0; i < nums.length; ++i) {
if (nums[i] == target) {
ans.add(i);
}
}
return ans;
}
}复杂度
时间
O(n log n)
排序是主导,n 个元素排序要 O(n log n);后面从头扫一遍收集下标是 O(n),加起来仍是 O(n log n)
空间
不计排序 O(1);计入排序 C plus plus / Java O(log n),Python 最坏 O(n)
除去输出列表,只用常数个辅助变量。若把排序内部开销计入:C plus plus 与 Java 的排序递归栈约 O(log n),Python 的 Timsort 最坏 O(n);不计排序则 O(1)
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 找出数组排序后的目标下标 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
能不能不排序,做到 O(n)?+
可以。不排序,只扫一遍数组,数出两件事:有多少个元素严格小于 target,记为 less;有多少个元素等于 target,记为 equal。排序后比 target 小的都排在它前面,所以第一个 target 一定落在下标 less,一共 equal 个,于是答案就是从 less 到 less 加 equal 减 1 这一串连续下标。这样只需一遍扫描,时间 O(n)、空间 O(1),比排序更快。
为什么目标块的起始下标正好等于比 target 小的元素个数?+
排序后,所有比 target 小的元素都排在 target 前面,占据了下标 0 到 less 减 1 这些位置,一共 less 个。紧接着的下一个位置,也就是下标 less,就是第一个等于 target 的元素。动画里比 3 小的只有一个 1,所以第一个 3 落在下标 1,正好对上。
这题的时间复杂度卡在哪?+
卡在排序,是 O(n log n)。收集下标那一遍扫描只有 O(n)。如果改用刚才说的计数法,连排序都省了,整体能降到 O(n),这是面试里一个很讨喜的优化点。
想听吴师兄把这道题讲给你听?
文字版和动画都随便看。开通图解算法年卡,可以听吴师兄声线把 找出数组排序后的目标下标 一步步讲透(全站 0 节语音精讲,持续扩充), 卡住的地方还有 AI 私教小欧就着动画帮你拆到懂。
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。