剑指 链表相关

package jianzhi

import (
	"fmt"
	"github.com/emirpasic/gods/maps/hashmap"
	"github.com/emirpasic/gods/stacks/linkedliststack"
	"sort"
)

//给定链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。

//Definition for singly-linked list.
 type ListNode struct {
     Val int
     Next *ListNode
}

// 方法:先将链表遍历,并读取val,存入数组中,对数组排序后,依次将值赋到链表中
func sortList(head *ListNode) *ListNode {
	if head == nil{
		return nil
	}
	var arr []int
	for node := head;node != nil; node = node.Next{
		arr = append(arr, node.Val)
	}
	sort.Ints(arr)
	for node ,index:= head,0;node != nil; node = node.Next{
		node.Val = arr[index]
		index++
	}
	return head
}


/*
给定一个单链表 L 的头节点 head ,单链表 L 表示为:

 L0 → L1 → … → Ln-1 → Ln
请将其重新排列后变为:

L0 → Ln → L1 → Ln-1 → L2 → Ln-2 → …

不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换
 */

//先遍历一遍,将结点全部入栈,并记录个数,得到N的值,之后再遍历,每次新插入一个出栈的元素,对末尾的next指向空
func reorderList(head *ListNode)  {
	if head == nil{
		return
	}
	stack1 := linkedliststack.New()
	var n int = 0
	for node := head;node != nil; node = node.Next{
		stack1.Push(node)
		n++
	}
	var node = head
	for index := 0;index < n; node = node.Next{
		index ++
		if index == n {
			break
		}
		res, ok := stack1.Pop()
		if ok {
			lastNode := res.(*ListNode)
			lastNode.Next = node.Next
			node.Next = lastNode
			node = node.Next
			index ++
		}
	}
	node.Next = nil
}

/*
给定单链表的头节点 head ,请反转链表,并返回反转后的链表的头节点
 */
func reverseList(head *ListNode) *ListNode {
	if head == nil{
		return nil
	}
	stack1:= linkedliststack.New()
	for node := head;node != nil; node = node.Next{
		stack1.Push(node)
	}
	var revHead *ListNode
	top, ok := stack1.Pop()
	if ok{
		revHead = top.(*ListNode)
	}
	var node = revHead
	for ;!stack1.Empty();{
		top, ok := stack1.Pop()
		if ok{
			topNode := top.(*ListNode)
			node.Next = topNode
			node = node.Next
		}
	}
	node.Next = nil
	return revHead
}

/*
给定一个链表的 头节点 head ,请判断其是否为回文链表。

如果一个链表是回文,那么链表节点序列从前往后看和从后往前看是相同的。
 */
//先遍历一遍 入栈, 再遍历一遍并同时与出栈的元素进行对比,如果都相等 则是回文
func isPalindrome(head *ListNode) bool {
	if head == nil{
		return true
	}
	stack1:= linkedliststack.New()
	for node := head;node != nil; node = node.Next{
		stack1.Push(node)
	}
	for node := head;!stack1.Empty();node = node.Next{
		top, ok := stack1.Pop()
		if ok{
			topNode := top.(*ListNode)
			if topNode.Val != node.Val{
				return false
			}
		}
	}
	return true
}

/*
给定一个链表数组,每个链表都已经按升序排列。

请将所有链表合并到一个升序链表中,返回合并后的链表。
 */
func mergeKLists(lists []*ListNode) *ListNode {
	if len(lists) == 0 {
		return nil
	}
	var headNode  []*ListNode
	var head *ListNode = nil
	for _, list := range lists{
		if list == nil{
			continue
		}
		if head == nil || list.Val < head.Val{
			head = list
		}
		headNode = append (headNode,list)
	}
	if head == nil{
		return nil
	}
	for curNode:= head;len(headNode) > 0 ;{
		minNodeIndex := 0
		for index, pNode := range headNode{
			if pNode.Val < headNode[minNodeIndex].Val{
				minNodeIndex = index
			}
		}
		if curNode != headNode[minNodeIndex]{
			curNode.Next  = headNode[minNodeIndex]
			curNode=curNode.Next
		}
		headNode[minNodeIndex] = headNode[minNodeIndex].Next
		if headNode[minNodeIndex] == nil{
			headNode = append(headNode[:minNodeIndex],headNode[minNodeIndex+1:]...)
		}
	}
	return head
}

/*
请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null。
 */
type Node struct {
	    Val int
	     Next *Node
	     Random *Node
}
//先遍历一遍, 把每个结点复制出来,并将复制结点存入map中, 【老结点】:新节点
func copyRandomList(head *Node) *Node {
	if head == nil{
		return nil
	}
	nodeMap := hashmap.New() // empty
	for node := head; node != nil; node=node.Next{
		var newNode = Node{node.Val,nil,nil}
		nodeMap.Put(node,&newNode)
	}
	for node := head; node != nil; node=node.Next{
		newNodeRes, _ := nodeMap.Get(node)
		newNode := newNodeRes.(*Node)

		if node.Next != nil{
			newNextNodeRes, _ := nodeMap.Get(node.Next)
			newNode.Next = newNextNodeRes.(*Node)
		}

		if node.Random != nil{
			newRdmNodeRes, _ := nodeMap.Get(node.Random)
			newNode.Random = newRdmNodeRes.(*Node)
		}
	}
	newNodeRes, _ := nodeMap.Get(head)
	return newNodeRes.(*Node)
}

/*
给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。

返回删除后的链表的头节点。
 */
func deleteNode(head *ListNode, val int) *ListNode {
	if head == nil{
		return nil
	}
	var resHead = head
	//先确定头结点没有要删除的
	for node:= head;node != nil && node.Val == val;node = node.Next{
		resHead = node.Next
	}
	if resHead == nil{
		return nil
	}
	for pre, node := resHead,resHead.Next;node != nil;node = node.Next{
		if node.Val == val{
			if node.Next != nil{
				node.Val = node.Next.Val
				node.Next = node.Next.Next
			}else{
				pre.Next = nil
			}
		}
		pre = node
	}
	return resHead
}


func TestMergeOrderList(){
	list1 := ListNode{1,&ListNode{2,&ListNode{4,&ListNode{4,&ListNode{5,nil}}}}}
	list2 := ListNode{0,&ListNode{1,&ListNode{1,&ListNode{1,nil}}}}
	list3 := ListNode{3,&ListNode{7,&ListNode{8,nil}}}
	var listArr = []*ListNode{&list1,&list2,&list3}
	res := mergeKLists(listArr)
	for ;res != nil;res =res.Next{
		fmt.Print(res.Val,"->")
	}
	fmt.Print("nil\n")
}


/*
输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。
 */
func reversePrint(head *ListNode) []int {
	if head == nil{
		return []int{}
	}
	mstack := linkedliststack.New()
	var revVal []int
	for node := head;node != nil;node = node.Next{
		mstack.Push(node)
	}
	for; !mstack.Empty();{
		top, ok :=mstack.Pop()
		if ok{
			node := top.(*ListNode)
			revVal = append(revVal,node.Val)
		}
	}
	return revVal
}

func reversePrint1(head *ListNode) []int {
	if head == nil{
		return []int{}
	}
	var revVal []int
	for node := head;node != nil;node = node.Next{
		revVal = append([]int{node.Val},revVal...)  //相当于每次插入都把数组的所有元素后移一位,时间复杂度O(N2)
	}

	return revVal
}

/*
输入两个递增排序的链表,合并这两个链表并使新链表中的节点仍然是递增排序的。
 */
func mergeTwoLists(l1 *ListNode, l2 *ListNode) *ListNode {
	if l1 == nil{
		return l2
	}else if l2 == nil{
		return l1
	}
	var (
		resHead *ListNode = &ListNode{}
		p1 = l1
		p2 = l2
		p = resHead
	)
	for ;p1!= nil && p2!= nil;	p = p.Next{
		newNode := ListNode{Next: nil}
		if p1.Val <= p2.Val{
			newNode.Val = p1.Val
			p1 = p1.Next
		}else{
			newNode.Val = p2.Val
			p2= p2.Next
		}
		p.Next = &newNode
	}
	if p1!=nil{
		p.Next = p1
	}else if p2 != nil{
		p.Next = p2
	}
	return resHead.Next
}

/*
输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点。

例如,一个链表有 6 个节点,从头节点开始,它们的值依次是 1、2、3、4、5、6。这个链表的倒数第 3 个节点是值为 4 的节点。
 */
//长度记为N   倒数第K个 是正数的第N-K+1;需遍历两遍  第一遍统计长度,然后第二遍找出结点
//两个指针一起走,p1先走K-1步,接着p1p2一起移动  当p1走到最后,p2指向倒数第k
//边界情况  head=nil, k>len链表总长
func getKthFromEnd(head *ListNode, k int) *ListNode {
	if head == nil{
		return nil
	}
	var (
		index = 0
		p1,p2 = head,head
	)
	for ;p1!=nil;p1=p1.Next{
		if  index > k-1{
			p2 = p2.Next
		}
		index ++
	}
	if index <= k-1{
		return nil
	}
	return p2
}


func TestGetKthFromEnd(){

	fmt.Println(getKthFromEnd(&ListNode{1,&ListNode{2,&ListNode{3,&ListNode{4,&ListNode{5,&ListNode{6,nil}}}}}},6).Val)
}

/*
输入两个链表,找出它们的第一个公共节点。
 */
//入栈 并对比两个栈顶元素,不一致时,下一个为公共结点
//边界情况:1 链表为空 2 其中一个链表是另一个的子集  2 完全相等 3 完全不等
func getIntersectionNode(headA, headB *ListNode) *ListNode {
	if headA == nil || headB == nil{
		return nil
	}
	stackA := linkedliststack.New()
	stackB := linkedliststack.New()
	for node := headA;node != nil;node = node.Next{
		stackA.Push(node)
	}
	for node := headB;node != nil;node = node.Next{
		stackB.Push(node)
	}
	for;(!stackA.Empty()) && (!stackB.Empty());{
		topA, _ := stackA.Peek()
		nodeA := topA.(*ListNode)
		topB, _ := stackB.Peek()
		nodeB := topB.(*ListNode)
		if nodeA != nodeB {
			break
		}
		stackA.Pop()
		stackB.Pop()
	}
	if !stackA.Empty(){
		topA, _ := stackA.Peek()
		return topA.(*ListNode).Next
	}
	if !stackB.Empty(){
		topB, _ := stackB.Peek()
		return topB.(*ListNode).Next
	}
	//完全相等
	return headA
}

func TestGetIntersectionNode(){
	headA := &ListNode{1,&ListNode{2,&ListNode{3,&ListNode{4,&ListNode{5,&ListNode{6,nil}}}}}}
	headB := headA
	res := getIntersectionNode(headA,headB)
	if res == nil{
		fmt.Println("nil")
	}	else{
		fmt.Println("完全相等:",res.Val)
	}


	headB = &ListNode{4,&ListNode{5,&ListNode{6,nil}}}
	headA = &ListNode{1,&ListNode{2,&ListNode{3,headB}}}
	res = getIntersectionNode(headA,headB)
	if res == nil{
		fmt.Println("nil")
	}	else{
		fmt.Println("子集:",res.Val)
	}

	headC := &ListNode{5,&ListNode{6,nil}}
	headA = &ListNode{1,&ListNode{2,&ListNode{3,&ListNode{4,headC}}}}
	headB = &ListNode{8,headC}
	res = getIntersectionNode(headA,headB)
	if res == nil{
		fmt.Println("nil")
	}	else{
		fmt.Println("Y型:",res.Val)
	}

	headA = &ListNode{1,&ListNode{2,&ListNode{3,&ListNode{4,&ListNode{5,&ListNode{6,nil}}}}}}
	headB = &ListNode{6,&ListNode{5,&ListNode{4,&ListNode{3,&ListNode{2,&ListNode{1,nil}}}}}}
	res = getIntersectionNode(headA,headB)
	if res == nil{
		fmt.Println("nil")
	}	else{
		fmt.Println("完全不等:",res.Val)
	}
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值