2年没有写博客了,主要这两年要么支教要么留学的,事情好多。。不过还好坚持下来了,编程也没有放弃
最近看到了一篇Leetcode上的题目,原题是这样的:
You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a linked list.
You may assume the two numbers do not contain any leading zero, except the number 0 itself.
Example:
Input: (2->4->3) + (5->6->4)
output: (7->0->8)
初看这题,要求使用链表来实现两个链表相加的操作,很明显考的就是数据结构的知识了,这道题需要先构建链表,然后分别定义头指针,循环对两个链表的元素相加,每次都需要记录进位,完整的代码如下
public class ListNode {
int val;
ListNode next;
ListNode(int x) { val = x; }
}
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
if(l1==null || l2==null){
return null;
}
ListNode res = new ListNode(0);
ListNode m = res;//指向链表的头部
ListNode p = l1,q=l2;
int carry = 0;
while(p!=null || q!=null){
int a = p!=null?p.val:0;
int b = q!=null?q.val:0;
int sum = a + b + carry;
carry = sum / 10; //进位
int val = sum % 10; //节点的值
ListNode node = new ListNode(val);
m.next = node;
m = node;
if(p!=null) p = p.next; //移动指针
if(q!=null) q = q.next;
}
if(carry!=0){
m.next = new ListNode(carry);
}
return res.next; //去掉头节点
}
}
然后自己通过单链表写了增删改查的操作,具体如下
package com.natsuki.lesson2;
/**
* @Author: xuzhiwei
* @Date: 2018-12-26
* @Description:
*/
public class NodeTest {
public static void main(String[] args) {
Node<Integer> list = create02(10);
showNodes(list);
Node<Integer> list2 = create02(20);
Node<Integer> link = new Node<>();
mergeLinkList(list,list2,link);
showNodes(link);
}
/**
* 倒序创建
* @return 链表
*/
public static Node<Integer> create01(int n){
Node<Integer> head = new Node<>();
for (int i = 0; i < n; i++) {
Node<Integer> node = new Node<>();
node.data = i;
node.next = head.next;
head.next = node;
}
return head;
}
/**
* 正序创建
* @return 链表
*/
public static Node<Integer> create02(int n){
Node<Integer> head = new Node<>();
Node<Integer> p = head;
for (int i = 0; i < n; i++) {
Node<Integer> node = new Node<>();
node.data = i;
node.next = null;
p.next = node;
p = node;
}
return head;
}
/**
* 插入节点
* @param index 插入的位置
* @param linkList 链表
* @param el 插入的元素
* @return true表示成功,false表示失败
*/
public static boolean insert(Node<Integer> linkList,int index,int el){
if (index<0) {
return false;
}
Node<Integer> p = linkList;
int j = 0;
//移动指针
while (p!=null && j<index){
p = p.next;
j++;
}
//一般是插入的位置超过了链表的大小
if (p==null) {
return false;
}
Node<Integer> node = new Node<>();
node.data = el;
node.next = p.next;
p.next = node;
return true;
}
/**
* 删除节点
* @param linkList 链表
* @param index 删除的位置
* @return true表示成功,false表示失败
*/
public static boolean delete(Node<Integer> linkList,int index){
if (index<0){
return false;
}
Node<Integer> p = linkList;
int j = 0;
//移动指针
while (p!=null && j<index){
p = p.next;
j++;
}
if (p==null || p.next==null){
return false;
}
p.next=p.next.next;
return true;
}
public static int find(Node<Integer> linkList,int index){
if (index<0) {
throw new IllegalArgumentException("index must greater than 0");
}
Node<Integer> p = linkList;
int j = 0;
while (p!=null && j<index){
p = p.next;
j++;
}
if (p==null){
throw new IllegalArgumentException("index may greater than size of linkList");
}
return p.data;
}
/**
* 遍历链表
* @param linkList 链表
* @param <T> 存储数据
*/
public static <T> void showNodes(Node<T> linkList){
Node<T> p = linkList;
while (p.next!=null){
p = p.next;
System.out.print(p.data+"\t");
}
}
/**
* 链表合并,将la和lb合并为lc
* @param la 按大小排序后的链表
* @param lb 按大小排序后的链表
* @param lc 合并之后的新链表,元素按大小排序
*/
public static void mergeLinkList(Node<Integer> la,Node<Integer> lb,Node<Integer> lc){
//p指向la的第一个元素
Node<Integer> p = la.next;
//q指向lb的第一个元素
Node<Integer> q = lb.next;
//r指向lc的头指针
Node<Integer> r = lc;
while (p!=null&&q!=null){
if (p.data<=q.data){
r.next = p;
r = p;
p = p.next;
} else {
r.next = q;
r = q;
q = q.next;
}
}
//将剩余的某一个链表的部分接上去
r.next = p!=null?p:q;
}
}
链表在执行插入或者删除操作的时候,不考虑位置的查询,其复杂度为O(1),我们一般在操作链表的时候,一般需要定义一个指向第一个元素的头节点,方便操作,然后需要定义一个指向头节点的指针,用于遍历。诀窍是Node p = listNode,就代表p指向listNode的地址,可以用p来修改listNode的属性,也可以通过p=p.next来将p指向第二个元素,实现p的移动。