少年的书桌上没有虚度的光阴
2024.10.5
大家好,我是小苏。
今天给大家分享一下近期我刷力扣链表题的一个技巧!
我们知道,链表和数组的重要区别之一是:
链表不支持随机访问,数组支持
我们可以根据这一特性:把链表当中的值放入数组当中,对数组进行操作。然后再把数组的值返还给链表。
这样做既有优点也有缺点
优点是:可以避免复杂的指针移动,操作简单
缺点是,空间复杂度高,违背出题人的本意
注:这种方法虽然比较low,可能也违背了出题人的本意,但是如果在去公司机试的时候,如果这种方法能够很快的通过 当然是最好的,如果不行,再用通法。
力扣的一大部分题目用这种方法可以解决。
具体例子
206.反转链表
给你单链表的头节点 head
,请你反转链表,并返回反转后的链表。
输入:head = [1,2,3,4,5] 输出:[5,4,3,2,1]
思路:
-
创建一个vectorv,遍历链表,把链表的值插入到v当中 -
反转数组,可以使用reverse函数 -
把v当中的值插入到链表当中
代码:
class Solution {
public:
ListNode* reverseList(ListNode* head) {
vector<int>v;
for(auto p=head;p!=NULL;p=p->next){
v.push_back(p->val);
}
reverse(v.begin(),v.end());
int i=0;
for(auto p=head;p!=NULL;p=p->next){
p->val=v[i];
i++;
}
return head;
}
};
图解:
148.排序链表
给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。
输入:head = [4,2,1,3] 输出:[1,2,3,4] 示例 2:
思路:
-
创建一个数组v,遍历链表,把链表的值插入到v当中 -
使用sort进行排序 -
把v当中的值插入到链表当中
代码:
class Solution {
public:
ListNode* sortList(ListNode* head) {
vector<int>ans;
ListNode newhead;
newhead.next=head;
ListNode*p=head;
for(ListNode*p=head;p!=NULL;p=p->next)
{
ans.push_back(p->val);
}
sort(ans.begin(),ans.end());
int i=0;
for(ListNode*p=head;p!=NULL,i<ans.size();p=p->next,i++){
p->val=ans[i];
}
return newhead.next;
}
};
图解:
23.合并K个升序链表
给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。
示例 1:
输入:lists = [[1,4,5],[1,3,4],[2,6]]
输出:[1,1,2,3,4,4,5,6]
解释:链表数组如下:
[
1->4->5,
1->3->4,
2->6
]
将它们合并到一个有序链表中得到。
1->1->2->3->4->4->5->6
思路:
-
使用STL的list容器,并使用merge函数进行合并 -
把list当中的数据给一个数组 -
最后把数组的元素放入重新构建的一个链表当中
代码:
class Solution {
public:
static void Insert_tail(ListNode*head,int val)
{
auto p=new ListNode(val);
auto q=head;
for(;q->next!=NULL;q=q->next)
{
;
}
p->next=q->next;
q->next=p;
}
ListNode* mergeKLists(vector<ListNode*>& lists) {
//使用STL的list容器
list<int>ans;
for(auto l:lists)
{
list<int>tmp;
for(auto p=l;p!=NULL;p=p->next)
{
tmp.push_back(p->val);
}
ans.merge(tmp);
tmp.clear();
}
//把list当中的数据给vector
vector<int>v;
for(auto it=ans.begin();it!=ans.end();it++)
v.push_back(*it);
//创建一个新的表头
auto head=new ListNode(0);
for(int i=0;i<v.size();i++)
{
Insert_tail(head,v[i]);
}
return head->next;
}
};
图解:
234.回文链表
给你一个单链表的头节点 head ,请你判断该链表是否为 回文链表 。如果是,返回 true ;否则,返回 false 输入:head = [1,2,2,1] 输出:true
思路:
-
创建一个vectorv遍历链表,把链表的值插入到v -
判断数组是否是回文数组 -
把v当中的值插入到链表当中
代码:
class Solution {
public:
bool isPalindrome(ListNode* head) {
vector<int>ans;
ListNode newhead;
for(ListNode*p=head;p!=NULL;p=p->next)
{
ans.push_back(p->val);
}
int i=0;
int j=ans.size()-1;
while(i<j)
{
if(ans[i]!=ans[j])
return false;
else
{
i++;
j--;
}
}
return true;
}
};
图解:
重排链表
给定一个单链表 L 的头节点 head ,单链表 L 表示为:
L0 → L1 → … → Ln - 1 → Ln 请将其重新排列后变为:
L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → … 不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
输入:head = [1,2,3,4] 输出:[1,4,2,3]
思路:和上面类似,也是可以先把链表当中的值放入数组当中,然后对数组进行操作。
代码:
class Solution {
public:
void reorderList(ListNode* head) {
if (!head || !head->next) {
return; // 空链表或只有一个节点的链表无需处理
}
// 1. 将链表节点值存入数组
vector<int> values;
ListNode* current = head;
while (current) {
values.push_back(current->val);
current = current->next;
}
int n = values.size();
// 2. 重新排列数组
vector<int> reorderedValues;
int left = 0;
int right = n - 1;
while (left <= right) {
if (left <= right) {
reorderedValues.push_back(values[left]);
left++;
}
if (right >= left) {
reorderedValues.push_back(values[right]);
right--;
}
}
// 3. 重构链表
current = head;
for (int val : reorderedValues) {
current->val = val;
current = current->next;
}
}
};
总结
我们可以根据链表不支持随机访问,数组支持随机访问的特点,把链表当中的数据先拷贝到数组当中,对数组进行一系列的操作,再把数组的内容拷贝到链表当中,这种方法可以解决力扣当中大部分的题目。