012-将单链表的每K个节点之间逆序

package com.my.util;
/**
 * 单向链表节点
 * */
public class SingleNode {
	public int value;
	public SingleNode next;
	public SingleNode(int data){
		this.value = data;
	}
}

package com.my.suanfa;

import java.util.Stack;

import com.my.util.SingleNode;

/**
 * 将单链表的每K个节点之间逆序
 * */
public class Solution09 {
	/**
	 * 方法一:
	 * 利用栈结构,时间复杂度O(N),额外空间复杂度O(K)
	 * */
	public SingleNode reverseKNodes1(SingleNode head, int k) {
		//如果k<2则不需要对链表做任何调整
		if(k < 2) {
			return head;
		}
		//定义临时变量记录特殊位置
		SingleNode newHead = head;
		SingleNode pre = null;
		SingleNode next = null;
		SingleNode cur = head;
		Stack<SingleNode> stack = new Stack<SingleNode>();
		//对链表进行调整
		while(cur != null) {
			next = cur.next;
			stack.push(cur);
			if(stack.size() == k) {
				//每当stack.size() == k时,新链表就会发生变化,而对于新链表最重要的标志就是头结点和尾节点
				//pre记录新链表的最后一个节点
				pre = resign1(stack, pre, next);
				//newHead记录新链表的头结点
				//cur此时记录的值是旧链表未反转时的最后一个节点,也就是反转后新链表的头结点
				newHead = newHead == head ? cur : newHead;
			}
			cur = next;
		}
		//返回新链表的头结点
		return newHead;
	}
	
	/**
	 * 该函数用来调整新链表并将新链表和旧链表连接起来
	 * left记录新链表调整部分的最后一个节点
	 * right记录新链表未调整部分的第一个节点
	 * */
	public SingleNode resign1(Stack<SingleNode> stack, SingleNode left, SingleNode right) {
		SingleNode cur = stack.pop();
		if(left != null) {
			//说明新链表中已经有节点,直接将下一个节点连接在新链表的末尾
			left.next = cur;
		}
		SingleNode next = null;
		while(!stack.isEmpty()) {
			next = stack.pop();
			cur.next = next;
			cur = next;
		}
		//此时新链表已经调整完毕,将新链表与旧链表连接起来,而此时的旧链表的第一个节点便是right记录的节点
		cur.next = right;
		//此时cur记录的便是新链表调整部分的最后一个节点
		return cur;
	}
	
	/**
	 * 方法二:不需要栈结构,在原链表中直接调整
	 * 时间复杂度O(N),额外空间复杂度O(1)
	 * */
	public SingleNode reverseKNodes2(SingleNode head, int k) {
		if(k < 2) {
			return head;
		}
		//定义变量记录特殊位置
		SingleNode pre = null;
		SingleNode next = null;
		SingleNode start = null;
		SingleNode end = head;
		int count = 1;
		while(end != null) {
			next = end.next;
			if(count == k) {
				//count == k 时需要调整链表
				//对于调整链表,重要的有三个位置,新链表的头结点,调整部分开始的位置,调整部分结束的位置
				//如果pre==null说明是第一组,那么这组的最后一个节点就是新链表的头结点
				head = pre == null ? end : head;
				//pre == null 说明新链表还没有开始调整,所以需要调整的部分的头结点为head
				//如果pre==null说明这是第一组,那么这组的第一个节点就是旧链表的头结点
				start = pre == null ? head : pre.next;
				resign2(pre, start, end, next);
				//调整完后pre记录调整部分的最后一个节点
				pre = start;
				//计数器归零
				count = 0;
			}
			count++;
			end = next;
		}
		return head;
	}
	
	/**
	 * 调整链表
	 * 参数的含义
	 * left:左边已经调整好的部分
	 * start:调整部分的第一个节点
	 * end:调整部分的最后一个节点
	 * right:右边未调整部分部分
	 * */
	public void resign2(SingleNode left, SingleNode start, SingleNode end, SingleNode right) {
		SingleNode pre = start;
		SingleNode cur = start.next;
		SingleNode next = null;
		//调整需要调整的部分
		while(cur != right) {
			next = cur.next;
			cur.next = pre;
			pre = cur;
			cur = next;
		}
		//如果left != null,说明左边有调整好的部分需要连接,连接未调整时的最后一个节点
		if(left != null) {
			left.next = end;
		}
		//未调整时的第一个节点连接右边
		start.next = right;
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值