链表的翻转

1.基础问题:
给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
示例:
给定 1->2->3->4, 你应该返回 2->1->4->3.
2.算法
这个基础问题比较简单,具体解法利用分治法的思想,将相邻两个节点看成一组,组内进行交换,组间再串联起来就可以解决这个问题了。

public class Solution24 {
	 public ListNode swapPairs(ListNode head) {
	        if (head==null||head.next==null)
				return head;
			ListNode pre=head,aft=head.next;
			//两节点互换
			pre.next=aft.next;
			aft.next=pre;
			
			//这一组交换完,下一组开始互换,并间组之间链接到一起
			pre.next=swapPairs(pre.next);
			return aft;
	    }
}

我这里是利用了递归,先算第一组,然后将剩下的链表节点当成新的链表进行递归翻转。算法的复杂度是O(N),因为链表有多少个节点就进行了多少次翻转操作。空间复杂度是O(N),因为整个链表就在递归过程中占用了链表大小的堆栈空间。
3.升级问题
给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。
示例:
给你这个链表:1->2->3->4->5
当 k = 2 时,应当返回: 2->1->4->3->5
当 k = 3 时,应当返回: 3->2->1->4->5
说明:
你的算法只能使用常数的额外空间。
你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。
4.算法
我对这题的思考是建立在前一个基础问题上的,刚开始也是根据分治法思想,先找出一组相对应的最后的翻转节点,然后组内进行翻转,再将组与组之间链接起来。但是在编写过程中忽略链表的一个特征就是链表重新链接需要先断开节点再链接,因为这步操作没有处理,使得我在处理K=3时少了一个节点,debug了半个多小时,最后看了leetcode的题解,对比自己的代码,才发现了这个致命错误。具体代码如下:

public class Solution25 {
	public ListNode reverseKGroup(ListNode head, int k) {
		 if(head==null || k==1 || head.next==null)
			 return head;
			 
		 ListNode dummy = new ListNode(0);
		 dummy.next = head;
		 ListNode pre = dummy;
		 ListNode end = dummy;
		 int i = 0;
		 
		 for (; i < k && end != null; i++) {//找到翻转节点
			 end = end.next;
           }
      //如果end==null或者i<k,说明k已经大于这一组的长度了,可以直接返回
		 if(i<k||end==null)	
			 return head;
		 
		 ListNode start = pre.next;
	     ListNode next = end.next;
	     end.next = null;	//链表断开
	     pre.next = reverse(start);
	     start.next = reverseKGroup(next,k);//重新链接
		 return dummy.next;
	 }
	 //翻转函数
    private ListNode reverse(ListNode head) {
		    ListNode pre = null;
		    ListNode curr = head;
		    while (curr != null) {
		        ListNode next = curr.next;
		        curr.next = pre;
		        pre = curr;
		        curr = next;
		    }
		    return pre;
		}
}

借鉴了题解,顺便把自己的代码改的比较容易理解和简洁。这样的话,这个算法的时间复杂度为 O(n*K), 最好的情况为 O(n) 最差的情况为O(n²),空间复杂度为 O(n),这点是没有满足使用常数级空间的要求,但是将上述代码改成非递归即可满足。非递归的如下链接 leetcode 25题 题解链接.
这个图用于帮助理解:
Alt

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
链表翻转是指将一个单向链表中的所有节点顺序翻转。以下是一个简单的C++程序实现链表翻转: ```c++ #include <iostream> using namespace std; struct ListNode { int val; ListNode *next; ListNode(int x) : val(x), next(NULL) {} }; ListNode* reverseList(ListNode* head) { ListNode* prev = NULL; ListNode* curr = head; while (curr != NULL) { ListNode* nextTemp = curr->next; curr->next = prev; prev = curr; curr = nextTemp; } return prev; } int main() { ListNode* head = new ListNode(1); head->next = new ListNode(2); head->next->next = new ListNode(3); head->next->next->next = new ListNode(4); cout << "Original list: "; ListNode* curr = head; while (curr != NULL) { cout << curr->val << " "; curr = curr->next; } cout << endl; head = reverseList(head); cout << "Reversed list: "; curr = head; while (curr != NULL) { cout << curr->val << " "; curr = curr->next; } cout << endl; return 0; } ``` 在上面的代码中,我们定义了一个ListNode结构体表示链表的节点,包含一个整数值和一个指向下一个节点的指针。reverseList()函数实现了链表翻转操作,它使用了三个指针prev、curr和nextTemp。prev指向上一个节点,curr指向当前节点,nextTemp指向下一个节点。在while循环中,我们不断将当前节点的指针指向上一个节点,然后更新三个指针的值以便继续循环。最后返回prev作为新链表的头节点。在main函数中,我们创建了一个包含四个节点的链表,并输出原始链表翻转后的链表

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值