主页 > 电脑硬件  > 

力扣刷题DAY2(链表/简单)

力扣刷题DAY2(链表/简单)
一、回文链表

回文链表

方法一:双指针 /** * 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: bool isPalindrome(ListNode* head) { vector<int> vals; while (head) { vals.emplace_back(head->val); head = head->next; } for (int i = 0, j = vals.size() - 1; i < j; i++, j--) { if (vals[i] != vals[j]) return false; } return true; } };

思路:把链表的值存入一个vector,然后首尾双指针判断值是否相等。

复杂度分析

时间复杂度:O(n),其中 n 指的是链表的元素个数。空间复杂度:O(n),其中 n 指的是链表的元素个数,我们使用了一个数组列表存放链表的元素值。

查漏补缺:

vals.emplace_back(head->val);

作用:将 head->val 的值直接构造到 vals 的末尾。

for (int i = 0, j = vals.size() - 1; i < j; i++, j--) { if (vals[i] != vals[j]) return false; }

作用:计算 vals 的size 。

方法二:快慢指针

快慢指针参考 详解双指针算法(一)之快慢指针

/** * 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: // 寻找中间结点(若有两个返回第二个) ListNode* midNode(ListNode* head) { ListNode* fast = head; ListNode* slow = head; while (fast && fast->next) { slow = slow->next; fast = fast->next->next; } return slow; } // 逆序 ListNode* reverse(ListNode* head) { ListNode* pre = nullptr; while (head) { ListNode* newnode = head -> next; head->next = pre; pre = head; head = newnode; } return pre; } bool isPalindrome(ListNode* head) { ListNode* mid = midNode(head); // 给后半段逆序 ListNode *head2 = reverse(mid); while (head2) { if (head->val != head2->val) { // 不是回文链表 return false; } head = head->next; head2 = head2->next; } return true; } };

复杂度分析

时间复杂度:O(n),其中 n 是链表的长度(节点个数)。空间复杂度:O(1)。

与这道题最类似的一道题(找终结点+反转)重排序链表

/** * 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: ListNode* reverse(ListNode* head) { ListNode* pre = nullptr; while (head) { ListNode* temp = head->next; head->next = pre; pre = head; head = temp; } return pre; } ListNode* midNode(ListNode* head) { ListNode* fast = head; ListNode* slow = head; while (fast && fast->next) { fast = fast->next->next; slow = slow->next; } return slow; } void reorderList(ListNode* head) { ListNode* mid = midNode(head); ListNode* head2 = reverse(mid->next); ListNode* head1 = head; mid->next = nullptr; while (head2) { ListNode* beh1 = head1->next; ListNode* beh2 = head2->next; head1->next = head2; head2->next = beh1; head1 = beh1; head2 = beh2; } } };

易错点1:

必须要让mid是前半部分的最后一个节点,mid->next是后半部分的第一个节点才行。

因为重排逻辑决定了必须要是123  45才能正确重排。

 易错点2:

由于mid是前半部分的最后一个节点,就必须显示规定一个 mid->next=nullptr,这样才能保证前后两段完全断开,保证重排逻辑正确。

二、环形链表

环形链表

方法一:快慢指针 class Solution { public: bool hasCycle(ListNode* head) { if (head == nullptr || head->next == nullptr) { return false; } ListNode* slow = head; ListNode* fast = head->next; while (slow != fast) { if (fast == nullptr || fast->next == nullptr) { return false; } slow = slow->next; fast = fast->next->next; } return true; } };

复杂度分析

时间复杂度:O(N),其中 N 是链表中的节点数。空间复杂度:O(1)。我们只使用了两个指针的额外空间。

类似题目:

快乐数

class Solution { public: int calcu(int n) { int res = 0; while (n) { res += (n % 10) * (n % 10); n /= 10; } return res; } bool isHappy(int n) { int slow = n; int fast = calcu(n); while (slow != fast) { slow = calcu(slow); fast = calcu(calcu(fast)); if (fast == 1) return true; } if (fast != 1) return false; else return true; } };

 疑点解析1:

会不会陷入无休止循环?不会。

 疑点解析2:

如果fast==slow!=1是否还要继续判断?不用。

因为二者相等时,说明slow已经进入了循环,不可能再出现1的情况了。

方法二:哈希表 /** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: bool hasCycle(ListNode *head) { unordered_set<ListNode*> visited; ListNode *x=head; while(x){ if(visited.count(x)) return true; visited.insert(x); x=x->next; } return false; } };

思路:使用哈希表来存储所有已经访问过的节点。每次我们到达一个节点,如果该节点已经存在于哈希表中,则说明该链表是环形链表,否则就将该节点加入哈希表中。重复这一过程,直到我们遍历完整个链表即可。

复杂度分析

时间复杂度:O(N),其中 N 是链表中的节点数。最坏情况下我们需要遍历每个节点一次。空间复杂度:O(N),其中 N 是链表中的节点数。主要为哈希表的开销,最坏情况下我们需要将每个节点插入到哈希表中一次。

标签:

力扣刷题DAY2(链表/简单)由讯客互联电脑硬件栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“力扣刷题DAY2(链表/简单)