算法63-求链表是否回文

题目:
给定一个链表的头结点,检查链表是否是回文,返回结果true or false

分析:

方法1;刚学过的求链表的中点,求出中点从中间向两边依次对比

方法2:利用栈,先将链表全部压入栈,之后从栈弹出的时候就相当于与将链表反转,正序遍历链表,与栈弹出的元素对比,每一个袁术都相同,返回true(为什么不从两端遍历,单向链表?)

代码:

package main
import (
	"errors"
	"fmt"
)
//链表本身,包含长度,头结点和尾节点,对于一个双向链表,
//我们只关注它的haea和tail,head和tail是一个个具体的节点
type LinkedList struct {
	len  int
	head *LinkedNode
	tail *LinkedNode
}
//链表中的一个节点的结构,包含节点的数据,前向指针,后向指针,指向的也是一个节点本身
type LinkedNode struct {
	data int
	next *LinkedNode
	prev  *LinkedNode
}
// type Data struct{
// 	key string
// 	data int
// }
//所有的操作都基于指针
func NewLinkedList() *LinkedList {
	return &LinkedList{
		len:  0,
		head: nil,
		tail: nil,
	}
}
//追加一个节点,链表没有头结点就把自己设为链表的头结点,头尾指针都指向自己
//有头结点就把自己放在最后,1先把自己的prev指向原来的tail,2把原来的tail的next指向自己,3把链表的tail设为自己
func (ll *LinkedList)Add(node *LinkedNode) {
	// node := &LinkedNode{
	// 	data: data,
	// }
	// fmt.Printf("hhhhhhead%v\n", ll.head)

	if ll.head==nil{
		ll.tail=node

		ll.head=node
	}else{
		// fmt.Printf("tttttail%v\n", ll.tail)
		node.prev=ll.tail

		ll.tail.next=node
		ll.tail=node
		
	}
	
	ll.len++//记得更新长度
}
//奇数返回中点 偶数返回上中点
func Midorupmid(head LinkedNode) *LinkedNode{
	if &head ==nil || head.next == nil || head.next.next == nil{//只有一个节点或两个节点时,返回头结点
		return &head
	}
	//慢指针一个定位在第二个节点,快指针定位在第三个节点
	slow:=head.next
	fast:=head.next.next
	for fast.next != nil && fast.next.next !=nil{
		slow=slow.next
		fast=fast.next.next
	}
	return slow
}	
//1 for里面的条件是&,不是||
//2 slow和 fast在前进过程中是不等距的,不能混淆
func Midordownmid(head LinkedNode) *LinkedNode{
	if &head ==nil || head.next == nil {//控制节点大于1,就可以进入下面的循环
		return &head//当head等于nil,head的next也等于nil,
	}
	//两个指针都初始化在head.next
	slow:=head.next
	fast:=head.next
	//节点数大于1进入
	for   fast.next !=nil && fast.next.next !=nil {//注意是and,必现同时满足
		slow=slow.next
		fast=fast.next.next//slow和fast不等距,所以不能用slow.next.next代替
		// fmt.Println(slow,fast)
	}
	return slow
}	
//
//利用链表找中点的方法
func ismirror(head LinkedNode) bool{
	//不知道链表长度是奇是偶,所以调用求中点和上下中点去分别找到两个指针,
	//1  既可以利用返回的两个指针再向两边移动去比值
	//2  在不知道奇偶的条件下也可以实现
	t1:=Midorupmid(head)
	t2:=Midordownmid(head)
	fmt.Println(t1,t2)
	if (*t1).data==(*t2).data{//值相等等
		fmt.Printf("true\n")

		for (*t1).data==(*t2).data  && t1.prev !=nil && t2.next !=nil{
			t1=t1.prev
			t2=t2.next
			fmt.Printf("ininin %v     %v  \n",t1,t2)

		}
		if t1.prev ==nil && t2.next ==nil && (*t1).data==(*t2).data {
			return true
		}
	}
	return false
}

type Stack []int

// 入栈
func (s *Stack) push(a int) {
	*s = append(*s, a)
}

// 出栈
func (s *Stack) pop() (int, error) {
	if (len(*s) == 0) {
		return 0, errors.New("Empty Stack")
	}
	a := *s
	defer func() {
		*s = a[:len(a) - 1]
	}()
	return a[len(a) - 1], nil
}
//借助栈实现,先将链表全部压入栈,再输出的时候相当于将链表反转
//栈弹出元素(倒序)与正序遍历链表的值对比,全相等就返回true
func ismirror1(head *LinkedNode)bool {
	node:=head
	var s Stack = make([]int,0)
	s.push(head.data)
	for head.next !=nil{
		s.push(head.next.data)
		head=head.next
	}
	fmt.Println(s)

	for node !=nil{
		t1,_:=s.pop()
		t2:=node.data
		fmt.Println(t1,t2)
		if t1 != t2{
			return false
		}

		node=node.next
		// fmt.Println(node)

	}
	return true

}

func main(){
	var head LinkedNode
	head.data=18

	var l1 LinkedNode
	l1.data=5

	var l2 LinkedNode
	l2.data=20

    var l3 LinkedNode
	l3.data=3

  
    var l4 LinkedNode
    l4.data=3

	var l5 LinkedNode
    l5.data=20

	var l6 LinkedNode
    l6.data=5

	var l7 LinkedNode
	l7.data=18

	list := NewLinkedList()
	list.Add(&head)
	list.Add(&l1)
	list.Add(&l2)
	list.Add(&l3)
	list.Add(&l4)
	list.Add(&l5)
	list.Add(&l6)
	list.Add(&l7)

	// fmt.Println(list.head)
	// fmt.Println(list.head.next)

	// fmt.Println(list.head.next.next)
	// fmt.Println(list.head.next.next.next)
	// fmt.Println(list.tail)

	// fmt.Println(Midorupmid(head))
	// fmt.Println(Midordownmid(head))
	// fmt.Println(beforeMidorupmid(head))
	// fmt.Println(aftereMidordownmid(head))
	fmt.Println(ismirror(head))
	fmt.Println(ismirror1(&head))
}

总结:

1 注意越界问题,f如判断ast.next.next是否nil,需保证第一个next不是nil
2 注意指针与值,结构体是指针,其中一个字段不是指针,取这个字段的值要用(*node).data

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值