当前位置:   article > 正文

链表算法-回文结构、两个链表公共节点_回文链表

回文链表

最近一直在刷算法,以前没有重视这块,偶然巧合下,想到了某几次的面试,虽然没有以这个为主,但是也都有问过算法的题,因为没有这方面的积累,所以心底里一直抗拒,最近也有时间,觉得还是要花时间学习研究算法的东西,锻炼锻炼逻辑思路和解决思路。

学习路程肯定是要把基础掌握好的,你得知道各个名词的含义,如链表是什么,单链表怎么实现,双链表怎么实现,你才能处理把握链表出的方向的算法题,如树,什么是二叉树,二叉搜索树,二三树,红黑树,你知道每个结构的定义以及特性,才能掌握和思考怎么处理,这一定是必然的。

今天弄几个链表算法

1.判断链表回文结构

1.对单链表逆顺序是否与原链表顺序相同,也就是回文链表,如1->2 ->1,那么1->2->1这个就是true,如1->2,那么逆序就是2->1那么就是false;

因为链表有个特点不知道长度,不能随机用下标访问数据,所以需要遍历到最后才能全部知道数据,这道题可以采用先遍历将链表数据存储到数组中,然后采用二分法进行前后对比数据,直到遇到不相等则直接退出循环,返回false,一直相等则就是链表的回文数据,

  1. public boolean isPail (ListNode head) {
  2. List<Integer> list = new ArrayList();
  3. ListNode w = head;
  4. // 将链表数据存储到数组中
  5. while (w != null) {
  6. list.add(w.val);
  7. w = w.next;
  8. }
  9. int size = list.size();
  10. boolean result = true;
  11. // 将数组长度/2 得到回文顺序交界点
  12. for (int i = 0; i < size / 2; i++) {
  13. // 从前往后对比直到交界点,全部都比对完毕
  14. if (list.get(i).equals(list.get(size - i - 1))) {
  15. } else {
  16. result = false;
  17. break;
  18. }
  19. }
  20. return result;
  21. }
  22. // 节点,是个内部类
  23. public static class ListNode {
  24. int val;
  25. ListNode next = null;
  26. }

测试示例

  1. ListNode ListNode = new ListNode();
  2. ListNode.val = 1;
  3. ListNode.next = null;
  4. ListNode ListNodeNext = new ListNode();
  5. ListNodeNext.val = 2;
  6. ListNodeNext.next = null;
  7. ListNode.next = ListNodeNext;
  8. ListNode ListNodeNextn = new ListNode();
  9. ListNodeNextn.val = 3;
  10. ListNodeNextn.next = null;
  11. ListNodeNext.next = ListNodeNextn;
  12. ListNode ListNodeNextns = new ListNode();
  13. ListNodeNextns.val = 3;
  14. ListNodeNextns.next = null;
  15. ListNodeNextn.next = ListNodeNextns;
  16. ListNode ListNodeNextnn = new ListNode();
  17. ListNodeNextnn.val = 2;
  18. ListNodeNextnn.next = null;
  19. ListNodeNextns.next = ListNodeNextnn;
  20. ListNode ListNodeNextnns = new ListNode();
  21. ListNodeNextnns.val = 1;
  22. ListNodeNextnns.next = null;
  23. ListNodeNextnn.next = ListNodeNextnns;
  24. System.out.println(AboutLinked.isPail2(ListNode));

输入:1->2->3->3-2>1返回结果 true

自己写的一个版本,当时主要考虑不想遍历放入数组中,再次进行遍历,所以用了String的字符串拼接方式。

  1. public boolean isPail (ListNode head) {
  2. String s="";
  3. String ss ="";
  4. ListNode w = head;
  5. while (w != null) {
  6. s+=w.val+"";
  7. ss=w.val+ss;;
  8. w = w.next;
  9. }
  10. return s.equals(ss);
  11. }

这种方式答案是对的,但是性能太差,输入量特多的情况下,会超时反馈不出结果,我想主要原因还是出在了字符串拼接导致的问题,我本想减少代码,减少一些遍历,但是却出现了其他的性能问题,不用StringBuffer的原因是想要倒着拼接,如果使用reverse则负数又会出现问题,

String采用连接运算符(+)效率低下,都是上述循环、大批量数据情况造成的,每做一次"+"就产生个StringBuilder对象,然后append后就扔掉。下次循环再到达时重新产生个StringBuilder对象,然后append字符串,如此循环直至结束。如果我们直接采用StringBuilder对象进行append的话,我们可以节省创建和销毁对象的时间。

2. NC66两个链表的第一个公共节点

输入两个非公共的链表{1,2,3}以及{4,5}和一个公共链表{6,7},塞入到两个公共链表里头,变为{1,2,3,6,7}以及{4,5,6,7},请输出他们的第一个公共节点,那么得到的就是{6,7}

我们需要两个链表一一比对,直到某个链表为空,另一个链表还有值时进行两个链表替换,然后继续对比,本示例当对比空以后将temp赋值为temp2{1,2,3,6,7},temp2赋值为temp则{4,5,6,7},当temp链表走到空时,temp2链表已经赋值为1,那么当temp为空时,就赋值temp2为4,此时temp就为2,就变成了2:4,3:5,6:6 相同直接结束循环,是不是清楚很多,那么代码如下

  1. public class Solution {
  2. public static class ListNode {
  3. int val;
  4. ListNode next = null;
  5. }
  6. // pHead1={1,2,3,6,7} pHead2={4,5,6,7}
  7. public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
  8. ListNode temp = pHead1;
  9. ListNode temp1 = pHead2;
  10. while (temp != temp1) {
  11. // 如果为空互相替换来找出公共节点
  12. temp = temp!=null?temp.next:pHead2;
  13. temp1 = temp1!=null?temp1.next:pHead1;
  14. }
  15. return temp;
  16. }
  17. }

咱们就不演示测试了否择还得遍历打印链表,本次案例结果返回6->7

2. NC69-链表中倒数最后k个结点

这个就是得到链表中倒数第几个结点,如 {1,2,3,4,5},然后传入2,则得到{4,5},传入3则得到链表倒数第三个以及之后的节点数据,如果链表的长度不足倒数得结点,则返回空节点

原链表为{1,2,3,4,5} 我需要让快指针走,走的终点是k,走到了k的值以后,再快慢链表一起走,最后返回慢指针就是想要的最后k个结点。

  • 先循环,循环从0开始到k结束,那么第一个循环,快链表指针(fast)={2,3,4,5}

  • 循环到1,fast={3,4,5},假如传的是2,那么循环到此则结束循环

  • 快指针已得到,进行while循环,终止条件是快指针为空,fast={4,5} slow={2,3,4,5}

  • fast={5},slow={3,4,5}

  • fast={},slow={4,5} 结束循环,得到{4,5}

这里可采用快慢指针的思想,这样代码实现就很简单,

  1. public ListNode FindKthToTail (ListNode pHead, int k) {
  2. ListNode fast = pHead;
  3. // 快的指针先走,按k的步长走,如果为空则链表代表不足k个节点,返回空
  4. for (int i = 0; i < k; i++) {
  5. if (fast == null)
  6. return null;
  7. fast = fast.next;
  8. }
  9. // 快指针提前走了指定步长,直到快指针为空,则我们需要的就是慢指针的节点
  10. ListNode slow = pHead;
  11. while(fast!=null){
  12. fast=fast.next;
  13. slow=slow.next;
  14. }
  15. return slow;
  16. }

我自己有写过一个,思想和这个差不多,但是写完还是比这个复杂了,我采取的是,循环达到k点,就记录一个节点,直到找到空,就把存储的节点的下一个拿到,也就是将{1,2,3,4,5} 循环到3的时候将fast={3,4,5},循环到4的时候判断达不到到k个节点就为空了,如果是,则直接返回,不是就继续last={4,5},这种方式太冗余了,还要进行空啊或者其他不足k的判断,所以我们还是学会和使用简洁方式

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/919486
推荐阅读
相关标签
  

闽ICP备14008679号