链表常见问题

链表常见问题

1
2
3
4
5
6
7
8
9
10
/**
* 单链表数据结构
*/
class Node {
int val;
Node next;
public Node(int val) {
this.val = val;
}
}

0x01 链表翻转

题目描述:

这道算法题,说直白点就是:如何让后一个节点指向前一个节点。

1
2
3
4
5
6
7
8
9
10
11
// 1.翻转链表
public static Node reverse(Node head) {
Node res = null;
while (head != null) {
Node h = head.next;
head.next = res;
res = head;
head = h;
}
return res;
}

0x02 两数相加

题目描述:

Leetcode:给定两个非空链表来表示两个非负整数。位数按照逆序方式存储,它们的每个节点只存储单个数字。将两数相加返回一个新的链表。

你可以假设除了数字 0 之外,这两个数字都不会以零开头。

示例:

1
2
3
输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 2.链表相加
public static Node plus(Node l1, Node l2) {
Node dummyHead = new Node(0);
Node l3 = dummyHead;
int carry = 0;
while (l1 != null || l2 != null || carry > 0) {
int val = carry;
val = (l1 != null ? val + l1.val : val);
val = (l2 != null ? val + l2.val : val);
Node t = new Node(val > 9 ? val - 10 : val);
l3.next = t;
carry = val > 9 ? 1 : 0;
l1 = l1 != null ? l1.next : null;
l2 = l2 != null ? l2.next : null;
l3 = t;
}
return dummyHead.next;
}

0x03 链表中倒数第k个节点

题目描述:

输入一个链表,输出该链表中倒数第k个结点。

问题分析:

链表中倒数第k个节点也就是正数第(L-K+1)个节点。

首先两个节点/指针,一个节点 node1 先开始跑,指针 node1 跑到 k-1 个节点后,另一个节点 node2 开始跑,当 node1 跑到最后时,node2 所指的节点就是倒数第k个节点也就是正数第(L-K+1)个节点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 3.链表中倒数第k个节点
public static Node findKFromEnd(Node head, int k) {
Node node1 = head, node2 = head;
int len = 0, index = k; // 链表长度
while (node1 != null) {
len++;
node1 = node1.next;

// 从 len = k -1 的位置开始,执行 K 次,
if (index > 0) {
index--;
} else {
node2 = node2.next;
}
}
if (len == 0 || len < k) return null;
return node2;
}

0x04 删除链表的倒数第N个节点

题目描述:

给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。

问题分析:

  • 两次遍历法

首先我们将添加一个 哑结点(dummyHead)作为辅助,该结点位于列表头部。哑结点用来简化某些极端情况,例如列表中只含有一个结点,或需要删除列表的头部。在第一次遍历中,我们找出列表的长度 L。然后设置一个指向哑结点的指针,并移动它遍历列表,直至它到达第 (L - n) 个结点那里。我们把第 (L - n)个结点的 next 指针重新链接至第 (L - n + 2)个结点,完成这个算法。

  • 一次遍历法:

链表中倒数第N个节点也就是正数第(L-N+1)个节点。 定义两个节点 node1、node2;node1 节点先跑,node1节点 跑到第 n+1 个节点的时候,node2 节点开始跑.当node1 节点跑到最后一个节点时,node2 节点所在的位置就是第 (L-n ) 个节点(L代表总链表长度,也就是倒数第 n+1 个节点)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 4.删除链表的倒数第N个节点
public static Node deleteKFromEnd(Node head, int k) {
Node dummyHead = new Node(0);
dummyHead.next = head;
int len = 0, index = k;
Node p1 = head, p2 = dummyHead;
while (p1 != null) {
len++;
p1 = p1.next;
if (index > 0) {
index--;
} else {
p2 = p2.next;
}
}
if (len >= k && k > 0) {
p2.next = p2.next.next;
}
return dummyHead.next;
}

0x05 合并两个有序的链表

题目描述:

输入两个单调递增的链表,输出两个链表合成后的链表,需要合成后的链表单调递增。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 5.合并两个排序的链表
public static Node merge(Node head1, Node head2) {
if (head1 == null) return head2;
if (head2 == null) return head1;
Node t = null;
if (head1.val < head2.val) {
t = head1;
t.next = merge(head1.next, head2);
} else {
t = head2;
t.next = merge(head1, head2.next);
}
return t;
}

Java内存模型JMM

Java内存模型

java内存模型(Java Memory Model,JMM)是java虚拟机规范定义的。

0x01.主内存与工作内存

java内存模型规定了所有的变量都存储在住内存。每条线程还有自己的工作内存,线程的工作内存中保存了被该线程使用到的主内存中的变量的拷贝。线程对变量的所有操作都必须在工作内存中进行,而不能直接读写主内存中的变量。不同线程之间也无法直接访问对方工作内存中的变量,线程间变量传递均需要通过主内存来完成。当多个线程操作的变量涉及到同一个主内存区域,将可能导致各自的工作线程数据不一致,这样就导致变量同步回主内存的时候可能冲突导致数据丢失。

阅读更多

KMP算法(Java版)

KMP算法(Java版)

谈到字符串问题,不得不提的就是 KMP 算法,它是用来解决字符串查找的问题,可以在一个字符串(S)中查找一个子串(W)出现的位置。KMP 算法把字符匹配的时间复杂度缩小到 O(m+n) ,而空间复杂度也只有O(m)。因为“暴力搜索”的方法会反复回溯主串,导致效率低下,而KMP算法可以利用已经部分匹配这个有效信息,保持主串上的指针不回溯,通过修改子串的指针,让模式串尽量地移动到有效的位置。

问题:

有一个文本串S,和一个模式串P,现在要查找P在S中的位置

0x01 暴力算法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 暴力查找法:不一致的时候直接把i 移动到 i+1 的位置继续比较
private static int search(String s, String p) {
int sLen = s.length();
int pLen = p.length();
int i = 0, j = 0;
while (i < sLen && j < pLen) {
if (s.charAt(i) == p.charAt(j)) {
// 字符相同,则继续匹配下一个字符
i++;
j++;
} else {
// i,j 复位
i = i - j + 1;
j = 0;
}
}
if (j == pLen) return i - j;
return -1;
}
阅读更多

十大排序算法实现(Java版)

十大排序算法实现(Java版)

一. 常用排序算法

1
2
3
4
5
// Java 的进制数表示
int a10 = 99;
int a2 = 0b101;
int a8 = 0143;
int a16 = 0x63;

0x01 冒泡排序

原理
比较相邻的元素。如果第一个比第二个大,就交换他们两个。 对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。 针对所有的元素重复以上的步骤,除了最后一个。 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

阅读更多

设计模式@Java

设计模式 Java版

设计模式(Design Pattern)的本质是面向对象设计原则的实际运用,是对类的封装性、继承性和多态性以及类的关联关系和组合关系的充分理解。正确使用设计模式具有以下优点:

  • 可以提高程序员的思维能力、编程能力和设计能力。
  • 使程序设计更加标准化、代码编制更加工程化,使软件开发效率大大提高,从而缩短软件的开发周期。
  • 使设计的代码可重用性高、可读性强、可靠性高、灵活性好、可维护性强。
阅读更多
Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×