算法-链表操作

题目

1)输入链表头节点,奇数长度返回中点,偶数长度返回上中点

2)输入链表头节点,奇数长度返回中点,偶数长度返回下中点

3)输入链表头节点,奇数长度返回中点前一个,偶数长度返回上中点前一个

4)输入链表头节点,奇数长度返回中点前一个,偶数长度返回下中点前一个

思路:快慢指针

// 奇数 arr[len/2]
// 偶数 arr[len/2-1]
// 中间偏上
public static Node midOrUpMidNode(Node head) {
		if (head == null || head.next == null || head.next.next == null) {
			return head;
		}
		// 链表有3个点或以上
		Node slow = head.next;
		Node fast = head.next.next;
		while (fast.next != null && fast.next.next != null) {
			slow = slow.next;
			fast = fast.next.next;
		}
		return slow;
	}

// 奇数 arr[len/2]
// 偶数 arr[len/2]
// 中间偏下
public static Node midOrDownMidNode(Node head) {
		if (head == null || head.next == null) {
			return head;
		}
		Node slow = head.next;
		Node fast = head.next;
		while (fast.next != null && fast.next.next != null) {
			slow = slow.next;
			fast = fast.next.next;
		}
		return slow;
	}

// 奇数 arr[len/2-1]
// 偶数 arr[len/2-2]
// 中间偏上前一个
public static Node midOrUpMidPreNode(Node head) {
		if (head == null || head.next == null || head.next.next == null) {
			return null;
		}
		Node slow = head;
		Node fast = head.next.next;
		while (fast.next != null && fast.next.next != null) {
			slow = slow.next;
			fast = fast.next.next;
		}
		return slow;
	}


// 奇数 arr[len/2-1]
// 偶数 arr[len/2-1]
// 中间偏上后一个
public static Node midOrDownMidPreNode(Node head) {
		if (head == null || head.next == null) {
			return null;
		}
		if (head.next.next == null) {
			return head;
		}
		Node slow = head;
		Node fast = head.next;
		while (fast.next != null && fast.next.next != null) {
			slow = slow.next;
			fast = fast.next.next;
		}
		return slow;
	}

题目:给定一个单链表的头节点head,请判断该链表是否为回文结构。

1)哈希表方法特别简单(笔试用)

2)改原链表的方法就需要注意边界了(面试用)

思路:快慢指针,将中间元素next指针指向null ,同时更不后半部分next指向前一节点。前后双指正向中间遍历,直到为任意指针为null,时间复杂度n ,空间复杂度1

public static boolean isPalindrome3(Node head) {
		if (head == null || head.next == null) {
			return true;
		}
		Node n1 = head;
		Node n2 = head;
		while (n2.next != null && n2.next.next != null) { // find mid node
			n1 = n1.next; // n1 -> mid
			n2 = n2.next.next; // n2 -> end
		}
		// n1 中点
		
		
		n2 = n1.next; // n2 -> right part first node
		n1.next = null; // mid.next -> null
		Node n3 = null;
		while (n2 != null) { // right part convert
			n3 = n2.next; // n3 -> save next node
			n2.next = n1; // next of right node convert
			n1 = n2; // n1 move
			n2 = n3; // n2 move
		}
		n3 = n1; // n3 -> save last node
		n2 = head;// n2 -> left first node
		boolean res = true;
		while (n1 != null && n2 != null) { // check palindrome
			if (n1.value != n2.value) {
				res = false;
				break;
			}
			n1 = n1.next; // left to mid
			n2 = n2.next; // right to mid
		}
		n1 = n3.next;
		n3.next = null;
		while (n1 != null) { // recover list
			n2 = n1.next;
			n1.next = n3;
			n3 = n1;
			n1 = n2;
		}
		return res;
	}

思路:空间换时间 将来链表后半部放入堆栈,空间复杂度O(n/2)

public static boolean isPalindrome2(Node head) {
		if (head == null || head.next == null) {
			return true;
		}
		Node right = head.next;
		Node cur = head;
		while (cur.next != null && cur.next.next != null) {
			right = right.next;
			cur = cur.next.next;
		}
		Stack<Node> stack = new Stack<Node>();
		while (right != null) {
			stack.push(right);
			right = right.next;
		}
		while (!stack.isEmpty()) {
			if (head.value != stack.pop().value) {
				return false;
			}
			head = head.next;
		}
		return true;
	}

题目:将单向链表按某值划分成左边小、中间相等、右边大的形式

思路:把链表放入数组里,在数组上做partition

public static Node listPartition1(Node head, int pivot) {
		if (head == null) {
			return head;
		}
		Node cur = head;
		int i = 0;
		while (cur != null) {
			i++;
			cur = cur.next;
		}
		Node[] nodeArr = new Node[i];
		i = 0;
		cur = head;
		for (i = 0; i != nodeArr.length; i++) {
			nodeArr[i] = cur;
			cur = cur.next;
		}
		arrPartition(nodeArr, pivot);
		for (i = 1; i != nodeArr.length; i++) {
			nodeArr[i - 1].next = nodeArr[i];
		}
		nodeArr[i - 1].next = null;
		return nodeArr[0];
	}

	public static void arrPartition(Node[] nodeArr, int pivot) {
		int small = -1;
		int big = nodeArr.length;
		int index = 0;
		while (index != big) {
			if (nodeArr[index].value < pivot) {
				swap(nodeArr, ++small, index++);
			} else if (nodeArr[index].value == pivot) {
				index++;
			} else {
				swap(nodeArr, --big, index);
			}
		}
	}

	public static void swap(Node[] nodeArr, int a, int b) {
		Node tmp = nodeArr[a];
		nodeArr[a] = nodeArr[b];
		nodeArr[b] = tmp;
	}

思路:分成小、中、大三部分,再把各个部分之间串起来

public static Node listPartition2(Node head, int pivot) {
        if (head == null)
            return null;
        Node lesshead = new Node(0);
        Node lesstail = lesshead;
        Node equalhead = new Node(0);
        Node equaltail = equalhead;
        Node morehead = new Node(0);
        Node moretail = morehead;

        Node cur = head;
        while (cur != null){
            if(cur.value == pivot){
                equaltail.next = cur;
                equaltail = equaltail.next;
            }else if (cur.value<pivot){
                lesstail.next = cur;
                lesstail = lesstail.next;
            }else{
                moretail = cur;
                moretail = moretail.next;
            }
            cur = cur.next;
        }
    	// 关键步骤在这里
        equaltail.next = morehead.next;
        lesstail.next = equalhead.next;
        return lesshead.next;
    }

你可能感兴趣的:(算法,算法,链表,java)