思路
暴力
令m = nums.length
,容易想到一个暴力的方法,记录一个长度为n
的布尔数组visit
,对于nums
中的每个元素,去链表中遍历查找对应的下标i
,置对应的visit[i] = true
,最后统计有多少个连续的true
即可。
时间复杂度为O(nm)
,估计会超时。
是否存在一个时间复杂度为
O(n+m)
的方法?
- 利用哈希表?将链表数据转化为
map
? 空间复杂度为O(n)
。
哈希表
根据题目中的已知条件:链表中的元素都是不同的,因此可以遍历一个链表从而做一个映射:value: idx
,将其存储在哈希表中。再通过一个上述的visit
数组来记录某下标元素是否被访问到。
最后统计visit
中有多少个连续的true
即可。
代码如下:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
// 暴力:O(nm)
// 有没有O(n+m)的方法?
int numComponents(ListNode* head, vector<int>& nums) {
map<int, int> m;
int n=0;
ListNode* cur = head;
while(cur != nullptr){
m[cur->val] = n++;
cur = cur->next;
}
vector<bool> visit(n);
for (const auto &item : nums){
visit[m[item]] = true;
}
int ans = 0;
for (int i = 0; i < n; ++i) {
// 统计下降沿的个数
if ((i==n-1 && visit[i]) || (visit[i] && !visit[i+1])){
ans++;
}
}
return ans;
}
};
因为需要额外记录两个内容:
map
和visit
,所以空间复杂度为O(n)
。
能否将空间复杂度继续降低呢?
集合
为什么要把链表中的元素做映射呢?遍历链表中元素的时候去
nums
中判断是否存在不就行了?
将nums
中的元素存入Set
中,后续遍历链表的是否直接判断是否有连续的节点即可。
代码如下:
class Solution {
public:
int numComponents(ListNode* head, vector<int>& nums) {
set<int> s;
for (auto& num :nums){
s.insert(num);
}
ListNode* node = head;
bool flag = false;
int ans = 0;
while(node != nullptr){
//上升沿,前一个元素不在nums中
if(!flag && s.find(node->val) != s.end()){
ans++;
flag = true;
} else if(s.find(node->val) == s.end()) {
flag = false;
}
node = node->next;
}
return ans;
}
};