题目描述
-
You are given the head of a linked list, and an integer k.
-
Return the head of the linked list after swapping the values of the kth node from the beginning and the kth node from the end (the list is 1-indexed).
-
现给出一个链表的头结点,以及一个整数k
-
将从头往尾数第k个结点和从尾往头数第k个结点进行交换之后,返回新的链表的头节点
测试样例
-
example1
-
Input: head = [1,2,3,4,5], k = 2 Output: [1,4,3,2,5]
-
example2
Input: head = [7,9,6,6,7,8,3,0,9,5], k = 5 Output: [7,9,6,6,8,7,3,0,9,5]
-
example3
Input: head = [1], k = 1 Output: [1]
-
example4
Input: head = [1,2], k = 1 Output: [2,1]
-
example5
Input: head = [1,2,3], k = 2 Output: [1,2,3]
-
constraints
- The number of nodes in the list is n.
1 <= k <= n <= 105
0 <= Node.val <= 100
- The number of nodes in the list is n.
思路分析
-
定位到某一个具体结点,就要找到对应的前一个结点,主要还是对于链表的查询遍历,整体的难度不大。
-
根据之前那道题的经验,一次遍历就可以实现。传送门
-
主要是两种思路
- 找到目标结点,单纯的交换值就行了
- 找到目标节点的前一个结点,是交换节点
-
我是通过交换目标结点的值实现的
具体实现
#include<iostream>
#include<sstream>
#include<vector>
using namespace std;
//定义轻型线性表
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 {
private:
//头节点之前的结点
ListNode priorHead;
public:
/*
* 描述:从末向头数第n个结点
* 返回:返回当前结点的前一个结点的索引
*/
ListNode* findLastNode(ListNode* head,int k){
//初始化头节点之前的结点,将之指向指针
priorHead.next = head;
//初始化两个指针,left和right,left指向目标节点的前一个结点,right遍历向尾结点
ListNode* left = &priorHead;
ListNode* right = head;
//right进行调整,调整间距
for (int i = 1; i < k && right ; ++i) {
right = right->next;
}
//如果是指向第一个结点,直接返回,right为空
if(!right || !right->next){
return left;
}
//将right和left同时向后进行遍历,知道最后一个结点
while(right->next){
right = right->next;
left = left->next;
}
//调整之后,返回首结点
return left;
}
/*
* 描述:交换对应序列的两个结点,并将交换之后的链表返回
* 参数:head是指头结点
* k是需要交换的结点的序列
* 返回:交换之后的链表的头节点
* 原理:找到两个目标节点,然后进行交换值
*/
ListNode* swapNodes(ListNode* head, int k) {
//找到目标结点,初始化两个指针,用于搜寻目标节点
ListNode* left = head;
ListNode* right;
//左边的结点,是当前的结点
for (int i = 1; i < k; ++i) {
left = left->next;
}
//右边的结点的前一个结点
right = findLastNode(head,k);
//交换对应的值
int temp = left->val;
left->val = right->next->val;
right->next->val = temp;
//返回最终结果
return head;
}
};
int main(int argc, char const *argv[])
{
//声明vector用来保存数组
vector<int> number;
//处理输入,形成对应的链表
string a = "";
getline(cin,a);
//去除开头和结尾
a = a.erase(0,1);
a = a.erase(a.size()-1,1);
//将分割之后的结果进行输出
stringstream sstr(a);
string token;
while(getline(sstr,token,',')){
number.push_back(atoi(token.c_str()));
}
//生成对应的链表
ListNode head(number.at(0));
ListNode *temp = &head;
for (int i = 1; i < number.size(); ++i)
{
temp->next = new ListNode(number.at(i));
temp = temp->next;
}
//目标节点
int n;
cin>>n;
Solution solution;
ListNode* result = solution.swapNodes(&head,n);
while(result){
cout<<result->val<<endl;
temp = result->next;
delete(result);
result = temp;
}
return 0;
}
事故现场
第一次提交
借鉴他人
ListNode* swapNodes(ListNode* head, int k) {
//n1指向从头往尾数第n个结点
//n2指向从尾往头数第n个结点
ListNode *n1 = nullptr, *n2 = nullptr;
//一次遍历完成的,p最终指向尾结点的后一个结点,p用来遍历整个过程
for (auto p = head; p != nullptr; p = p->next) {
//当n2和P之间形成了间距,n2就开始和p一块向后进行遍历
n2 = n2 == nullptr ? nullptr : n2->next;
//正向遍历的过程,也是形成间距的过程
if (--k == 0) {
n1 = p;
n2 = head;
}
}
//交换对应的结点的值
swap(n1->val, n2->val);
return head;
}
- 不得不说,人家的代码,比我的简洁多了,思想虽然差不多,但是我就不连贯,是分段解决得。
- 在找寻从尾结点向头结点数第n个结点时候,已经遍历到了正向第n个结点,所以,这完全是一个过程。