题目
思路
初看题目似乎有点难理解,细看首先粗体字告诉我们链表内所有整型都是唯一的,第二点给的数组nums里面的数在链表内,所求就是nums里面的数放回链表内可以分成多少个连续的块。 比如:
linklist = [1,2,3,4,5]
nums = [1,2,4,5]
链表内12就是一块, 45就是一块,答案就是2,如果nums里面多了一个3,那么12345就是一块,答案就是1,并且答案与nums数组里面数字的顺序无关。
那么解题的思路就是,遍历整个链表,如果当前的数在nums数组中存在,并且链表的前一个数不在nums数组中则答案+1。这样就需要一个pre记录前一个链表值是否在nums数组中,当前值不在则给pre赋值为false,反之为true。这种思路的时间复杂度为O(n)。
然后是find的部分,因为看到给定整型的值的范围为
1 <= n <= 10000
所以我第一时间想到了用桶来装nums数组,实现思路为
int busket[10001] = {0};
for (int i = 0; i < nums.size(); i ++) {
busket[nums[i]] = 1;
}
然后遍历链表时只需要判断busket[val]是否为1就可以确定val是否在nums数组中了。这样空间复杂度为O(n)。
这样的思路看起来很合理,于是代码如下
class Solution {
public:
int numComponents(ListNode* head, vector<int>& nums) {
int busket[10001] = {0};
for (int i = 0; i < nums.size(); i ++) {
busket[nums[i]] = 1;
}
int ans = 0;
bool pre = false;
ListNode* node = head;
while(node) {
if(busket[node->val]) {
if(!pre) ans ++;
pre = true;
} else {
pre = false;
}
node = node -> next;
}
return ans;
}
};
结果也十分顺利
然后看了看评论,可以使用集合来装nums数组,因为c++有set类所以也非常方便,并且在适用于整型较大的情况,于是小改一下代码
class Solution {
public:
int numComponents(ListNode* head, vector<int>& nums) {
set<int> num;
for (int i = 0; i < nums.size(); i ++) {
num.insert(nums[i]);
}
int ans = 0;
bool pre = false;
ListNode* node = head;
while(node) {
if(num.count(node->val)) {
if(!pre) ans ++;
pre = true;
} else {
pre = false;
}
node = node -> next;
}
return ans;
}
};
顺便复习一下set的用法,不过用这种方法时间和内存都稍大一些,在这题中还是前一种方法更适合一些。
反思
1、这道题总体来说难度不算很大,主要是要理解题目的意思,刚阅读时会想考虑nums和链表中数的顺序会不会对结果造成影响,但实际上不会。如果题目改成链表和nums数组中有多少个相同的连续块那么
linklist = [1,2,3,4,5]
nums = [5,4,3,1,2]
这种情况下[1,2]就是1块,[3],[4],[5]都单独为一块,答案为4,解题思路应该就会变成搜索,时间复杂度就变成O() (也许有更好的方法),代码就会相对复杂一些。
2、在遇到整型数字较小的,涉及排序查找的情况,可以多思考使用类似桶排序的思路。
3、vector大小是size不是length。
4、不同容器的插入方法不要记混,比如set插入用insert不是push。