今日题目
- 题目1: 把两个长短链表按照顺序每一位相加后返回新的链表(难)
- 题目2: 把两个有序链表合并后返回新的有序链表(中)
今日心得
- 直接看算法答案是不能提高算法水平的,算法最重要的就是解题思路而非编码。看了别人的思路去实现会少了最重要的部分。
- 基本功就是数据结构的基本操作。比如链表结构以及如何遍历链表。如果这些知识都不具备。面试是不可能写出代码的,因为基本人你很难构思出如何遍历链表。
算法编码
链表结构
package linklist;
import java.util.List;
/**
* @ClassName ListNode
* @Description 单项链表
* @Author kouryoushine
* @Date 2022/5/13 23:23
* @Version 1.0
*/
public class ListNode {
int value;
ListNode next;
int length;
public ListNode(int value) {
this.value = value;
}
public static ListNode randListNode(int maxLengh, int maxValue) {
int first = (int) (Math.random() * maxValue);
int length = (int) (Math.random() * maxLengh);
ListNode listNode = new ListNode(first);// first节点
ListNode tail = listNode;
for (int i = 0; i < length; i++) {
int val = (int) (Math.random() * maxValue);
ListNode node = new ListNode(val);
tail.next = node;
tail = node;
}
listNode.length=length+1;
return listNode;
}
public void printListNode() {
ListNode head = this;
System.out.println(" ");
System.out.println("print list node ------------------------------");
while (head != null) {
System.out.print(head.value);
head = head.next;
}
}
public int listLength() {
int length = 0;
ListNode head = this;
while (head != null) {
length++;
head = head.next;
}
return length;
}
}
两个数字链表相加
package linklist;
import java.util.List;
/**
* @ClassName AddTwoNumberListNode
* @Description 两个数字链表相加
* 链表L: 3->8->9->9->9
* 链表S: 1->8->3
* 加法:逐位相加,大于10则进1 , 4->6->3->0->0->1
* @Author kouryoushine
* @Date 2022/5/13 23:25
* @Version 1.0
*/
//难点在于理解构思如下算法
//对数器不知道怎么写
public class AddTwoNumberListNode {
public static void main(String[] args) {
ListNode list1 = ListNode.randListNode(10, 9);
list1.printListNode();
ListNode list2 = ListNode.randListNode(10, 9);
list2.printListNode();
ListNode result = addTwoNumberList(list1, list2);
result.printListNode();
}
public static ListNode addTwoNumberList(ListNode list1, ListNode list2) {
//获取
int length1 = list1.listLength();
int length2 = list2.listLength();
ListNode l = length1 > length2 ? list1 : list2; //长链表的头部
ListNode s = l == list1 ? list2 : list1; //短链表的头
ListNode curS = s;//初始定位在短链
ListNode curL = l;//初始定位在长链头部
ListNode lastL = null;//长节点的最后一个位置
int carry = 0;//进位非常重要
//将相加过程分为三个阶段
//phase1: shortlist not null
while (curS != null) {
int sum = curL.value + curS.value + carry;
carry = sum >= 10 ? 1 : 0;//是否进位 等价于 sum/10
curL.value = sum % 10; //当前位置的结果
curS = curS.next; //下标右移动
curL = curL.next; //下标右移动
}
//phase2: longlist not null
while (curL != null) { //继续读长数组
int sum = curL.value + carry;
carry = sum >= 10 ? 1 : 0;//是否进位
curL.value = sum % 10; //当前位置的结果
lastL = curL; //最后一位
curL = curL.next; //下标右移动
}
//phase3: after read all
if (carry == 1) { //需要把carry作为新的节点添加到尾部
ListNode lastnode = new ListNode(carry);
lastL.next = lastnode;
}
return l;// 返回长链表(用长链表保存相加的结果)
}
}
有序链表合并,合并后依然是有序链表
package linklist;
import java.util.ArrayList;
/**
* @ClassName MergeOrderedListNode
* @Description 有序链表合并,合并后依然是有序链表
* * 链表1: 1->3->4->6->7
* * 链表2: 1->2->6
* 结果: 1-1-2-3-4-6-6-7
* @Author kouryoushine
* @Date 2022/5/14 0:56
* @Version 1.0
*/
public class MergeOrderedListNode {
//感觉比较简单,链表遍历熟悉的话
public static void main(String[] args) {
ListNode left=new ListNode(1);
ListNode left1 =new ListNode(3);
ListNode left2 =new ListNode(4);
ListNode left3 =new ListNode(6);
ListNode left4 =new ListNode(7);
left.next=left1;
left1.next=left2;
left2.next=left3;
left3.next=left4;
left.printListNode();
ListNode right=new ListNode(1);
ListNode right1 =new ListNode(2);
ListNode right2 =new ListNode(6);
right.next=right1;
right1.next=right2;
right.printListNode();
ListNode merge = mergeOrderedListNode2(left, right);
merge.printListNode();
// ArrayList<ListNode> listNodes = mergeOrderedListNode(left, right);
// for (int i = 0; i < listNodes.size(); i++) {
// System.out.println(listNodes.get(i).value);
// }
}
/**
* 借助队列自己实现了一个版本,队列可以用ArrayList代替
* @param left
* @param right
* @return
*/
public static ArrayList<ListNode> mergeOrderedListNode(ListNode left, ListNode right) {
ListNode curL = left;
ListNode curR = right;
ArrayList<ListNode> linkedQueue = new ArrayList<>();
while (curL != null || curR != null) { //任意一个有值就继续读
int valL = curL != null ? curL.value : Integer.MAX_VALUE; //为空则给最大值
int valR = curR != null ? curR.value : Integer.MAX_VALUE; //为空则给最大值
if (valL == valR) {
linkedQueue.add(curL);
linkedQueue.add(curR);
curL = curL.next;
curR = curR.next;
} else if (valL > valR) {
linkedQueue.add(curR);
curR = curR.next;
} else {
linkedQueue.add(curL);
curL = curL.next;
}
}
return linkedQueue;
}
/**
* 看一下链表的标准算法,比自己想的好很多。看答案很简单,自己构思出来不容易
*/
public static ListNode mergeOrderedListNode2(ListNode left,ListNode right){
//选择最小的头部作为最终头部
ListNode head = left.value<=right.value?left:right;
ListNode curL= head==left?left.next:left; //跳过头部
ListNode curR= head==right?right.next:right; //跳过头部
ListNode pre =head;//缓存前一个节点
while (curL!=null && curR!=null){//两边都有值时比较
if(curL.value<=curR.value){
pre.next=curL;
pre=curL;
curL=curL.next;
}else {
pre.next=curR;
pre=curR;
curR=curR.next;
}
pre.next=curL==null?curR:curL;
}
return head;
}
}