
文章前言
- 【一起学算法】专栏持续更新中,会在这里记录算法学习的过程
- 文末获取【一起学算法】
Github仓库手写算法源码
,一起跟着写一遍吧~- 【一起学算法】中所涉及的部分关于
leetcode
中的原题均可在leetcode官网的运行器通关~
单向链表
节点结构
/**
* @author Rhys.Ni
* @version 1.0
* @date 2021/12/5 9:59 上午
* @Description 单向链表节点结构
*/
public class Node<T> {
public T value;
public Node<T> next;
public Node(T value) {
this.value = value;
}
}
题记
单链表反转
- 思路图解
-
关键代码
//a -> b -> c -> null //null <- a <- b <- c public static Node reverse(Node head) { Node pre = null; Node next = null; while (head != null) { //提前记录next节点 next = head.next; //将头结点的下一个节点指向Pre head.next = pre; //pre移动到当前头节点位置 pre=head; //头结点移动到提前记录的next位置 head=next; } //当head为null时说明已经到头了,此时应该返回pre所在位置的节点作为头结点 return pre; }
##双向链表
节点结构
/**
* @author Rhys.Ni
* @version 1.0
* @date 2021/12/5 10:35 上午
* @Description
*/
public class DoubleNode<T> {
public T value;
public DoubleNode<T> pre;
public DoubleNode<T> next;
public DoubleNode(T value) {
this.value = value;
}
}
题记
双向链表反转
-
思路图解
-
关键代码
public static DoubleNode<Integer> reverse(DoubleNode<Integer> head) { DoubleNode<Integer> pre = null; DoubleNode<Integer> next = null; while (head != null) { //首先记录next节点 next = head.next; //将当前头节点的下一个节点指向当前pre所在的地址 head.next = pre; //将当前头结点的上一个节点指向原来next的地址 head.last = next; //将pre标志移动到当前头的位置 pre = head; //将next变为头结点 head = next; } //当头结点到达Null的时候说明pre是最后一个有效头节点 return pre; }
K个节点的组内逆序调整
给定一个单链表的头节点head,和一个正数k,实现k个节点的小组内部逆序,如果最后一组不够k个就不调整
例子: 调整前:1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8,k = 3
调整后:3 -> 2 -> 1 -> 6 -> 5 -> 4 -> 7 -> 8
-
思路图解
-
关键代码
/** * @author Rhys.Ni * @version 1.0 * @date 2021/12/16 8:34 下午 * @Description Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode() {} * ListNode(int val) { this.val = val; } * ListNode(int val, ListNode next) { this.val = val; this.next = next; } * } * 力扣原题:https://leetcode-cn.com/problems/reverse-nodes-in-k-group/?utm_source=LCUS&utm_medium=ip_redirect&utm_campaign=transfer2china */ public class ReverseKGroup<T> { public ListNode reverseKGroup(ListNode head, int k) { ListNode start = head; ListNode groupEnd = findGroupEnd(start, k); //凑不够一组直接返回当前头节点 if (groupEnd == null) { return head; } //第一组满足K个 head = groupEnd; reverse(start, groupEnd); //上一组的最后一个节点(其实就是上一组的开始节点,经过反转后成为最后一个节点) ListNode lastEnd = start; //当上一组的最后一个节点不指向Null的时候(如果最后没凑够一组也是会返回Null的) while (lastEnd.next != null) { //将上一组最后一个节点的下一个节点设置为下一组的开始节点 start = lastEnd.next; groupEnd = findGroupEnd(start, k); if (groupEnd == null) { return head; } reverse(start, groupEnd); //上一组反转后的最后一个节点指向这一组的结束节点 lastEnd.next = groupEnd; //将下一组的开始节点设置为反转后的最后一个节点 lastEnd = start; } return head; } /** * 组内反转 * * @param start * @param groupEnd * @return */ public void reverse(ListNode start, ListNode groupEnd) { ListNode pre = null; ListNode curr = start; //代名词为:本组反转操作的最后标志位,实际为下一组的开始节点 ListNode operationEnd = groupEnd.next; //如果Curr标志位跳到操作终止节点代表本组反转已经结束 while (curr != operationEnd) { ListNode next = curr.next; curr.next = pre; pre = curr; curr = next; } //本组的开始节点(反转后应该是最后一个节点),指向下一组的开始节点 start.next = operationEnd; } /** * 找每组最后一个节点 * * @param start * @param k * @return */ public ListNode findGroupEnd(ListNode start, int k) { while (--k != 0 && start != null) { start = start.next; } return start; } public class ListNode { int val; ListNode next; ListNode() { } ListNode(int val) { this.val = val; } ListNode(int val, ListNode next) { this.val = val; this.next = next; } } }
两个链表相加
给定两个链表的头节点head1和head2,认为从左到右是某个数字从低位到高位,返回相加之后的链表
例子 4 -> 3 -> 6 -> 9 3 -> 5 -> 4
返回 7 -> 8 -> 0 -> 0 -> 1
解释 9634 + 453 = 10087
-
思路图解
-
关键代码
//长短链表题 //共分为三阶段: //一阶段:长链表有,短链表有 //二阶段:长链表有,短链表无 //三阶段:长链表无,短链表无 /** * @author Rhys.Ni * @version 1.0 * @date 2021/12/20 10:57 下午 * @Description 两链表相加 * @leetcode:https://leetcode.com/problems/add-two-numbers/ */ public class AddTwoNumbers { public ListNode addTwoNumbers(ListNode head1, ListNode head2) { int len1 = calcLength(head1); int len2 = calcLength(head2); ListNode longNode = len1 >= len2 ? head1 : head2; ListNode shortNode = longNode == head1 ? head2 : head1; ListNode currL = longNode; ListNode currS = shortNode; ListNode last = null; int carry = 0; int nodeSum = 0; //一阶段:长短链表都有的情况 直接判断短链表是否为NULL得知是否一阶段结束 while (currS != null) { nodeSum = currL.val + currS.val + carry; currL.val = nodeSum % 10; carry = nodeSum / 10; last = currL; currL = currL.next; currS = currS.next; } //二阶段,长链表有,短链表无 while (currL != null) { nodeSum = currL.val + carry; currL.val = nodeSum % 10; carry = nodeSum / 10; last = currL; currL = currL.next; } //三阶段:长短链表都无,校验进位信息决定是否补新节点 if (carry != 0) { last.next = new ListNode(1); } return null; } /** * 计算链表长度 * * @param node * @return */ public int calcLength(ListNode node) { int length = 0; while (node != null) { length++; node = node.next; } return length; } public class ListNode { int val; ListNode next; ListNode() { } ListNode(int val) { this.val = val; } ListNode(int val, ListNode next) { this.val = val; this.next = next; } } }
两个有序链表的合并
-
思路图解
-
关键代码
/** * @author Rhys.Ni * @version 1.0 * @date 2021/12/22 8:35 下午 * @Description 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 * @leetcode:https://leetcode-cn.com/problems/merge-two-sorted-lists/ */ public class MergeTwoLists { public ListNode mergeTwoLists(ListNode list1, ListNode list2) { if (list1 == null || list2 == null) { return list1 == null ? list2 : list1; } //找到最小的作为头节点(升序链表) ListNode head = list1.val <= list2.val ? list1 : list2; ListNode pre = head; ListNode curr1 = head.next; ListNode curr2 = head == list1 ? list2 : list1; //两链表都有节点 while (curr1 != null && curr2 != null) { if (curr1.val <= curr2.val) { pre.next = curr1; curr1 = curr1.next; } else { pre.next = curr2; curr2 = curr2.next; } pre = pre.next; } //仅剩一个链表有节点 pre.next = curr1 == null ? curr2 : curr1; return head; } public class ListNode { int val; ListNode next; ListNode() { } ListNode(int val) { this.val = val; } ListNode(int val, ListNode next) { this.val = val; this.next = next; } } }
源码获取地址
加油小伙伴~ 点击获取算法篇代码~