All

Java注解
2019 年 12 月 06 日

注解,这个经常在开发中使用到的东西,它的使用语法是怎么样的?如何去自定义一个注解呢?

什么是注解

我们在日常开发中,比如 java 中的@Override,在 springboot 中用到的@SpringBootApplication等一系列标注在类或者方法上的注解。我们添加上注解后会有对应的事件处理,比如我们的@Override注解标明这个方法是重写了父类或者接口的方法,当参数不一致、返回类型不一致等不符合重写的要求时,编译器会报错。类似的@SpringBootApplication也是标明这个项目的一个 springboot 项目,默认会启动一个 tomcat 容器等。

注解是从 jdk5 开始引入的新特性。

注解的语法

1
public @interface FirstAnnotation {}

通过@interface即可声明一个注解。

K个一组翻转链表-LeetCode25
2019 年 11 月 27 日

题目描述

给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。 k 是一个正整数,它的值小于或等于链表的长度。 如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。 示例 : 给定这个链表:1->2->3->4->5 当 k = 2 时,应当返回: 2->1->4->3->5 当 k = 3 时,应当返回: 3->2->1->4->5 说明 : 你的算法只能使用常数的额外空间。 你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换

解题思路

首先根据 k,分隔每一组。将这一组反转,将下面的一组递归调用函数,然后将这一组的最后一个节点(就是参数中的头结点)与下一组反转后的头结点相连接。

反转一个单链表-LeetCode206
2019 年 11 月 24 日

题目描述

反转一个单链表。

示例:

输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL

进阶: 你可以迭代或递归地反转链表。你能否用两种方法解决这道题?

用队列实现栈-LeetCode225
2019 年 11 月 24 日

题目描述

使用队列实现栈的下列操作: push(x) – 元素 x 入栈 pop() – 移除栈顶元素 top() – 获取栈顶元素 empty() – 返回栈是否为空 注意:

你只能使用队列的基本操作– 也就是 push to back, peek/pop from front, size, 和 is empty 这些操作是合法的。 你所使用的语言也许不支持队列。 你可以使用 list 或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。 你可以假设所有操作都是有效的(例如, 对一个空的栈不会调用 pop 或者 top 操作)。

解题思路

  1. 使用两个队列

    将元素添加到第一个队列中。

    在获取元素时,将第一个队列中除了最后一个元素都添加到第二个队列中,剩下的这个就是要返回的元素。

    将两个队列进行交换,这样在添加元素时都能放到第一个队列中。

    使用一个变量来存储最后一个元素,这样在调用 top 方法时直接返回这个变量即可。

    用双队列实现栈

  2. 使用一个队列

    添加元素时添加到队列中,然后将队列中的元素除了最后一个再重新放入一遍

    在获取元素和查看元素时都拿第一个即可

    用一个队列实现栈

用栈实现队列-LeetCode232
2019 年 11 月 24 日

题目描述

使用栈实现队列的下列操作:

push(x) – 将一个元素放入队列的尾部。 pop() – 从队列首部移除元素。 peek() – 返回队列首部的元素。 empty() – 返回队列是否为空。 示例:

MyQueue queue = new MyQueue();

queue.push(1); queue.push(2);
queue.peek(); // 返回 1 queue.pop(); // 返回 1 queue.empty(); // 返回 false 说明:

你只能使用标准的栈操作 – 也就是只有 push to top, peek/pop from top, size, 和 is empty 操作是合法的。 你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。 假设所有操作都是有效的 (例如,一个空的队列不会调用 pop 或者 peek 操作)

解题思路

栈(先进后出)来实现队列(先进先出)。

可以用两个栈来实现,第一个栈存储,当进行 peek 或 pop 操作时,将第一个栈内元素按照先进后出的原则拿出来放到第二个栈里面。这时第二个栈里面在取就是我们总的第一个元素。

用栈实现队列

题目描述

给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。

你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

示例:

给定 1->2->3->4, 你应该返回 2->1->4->3.

可以看出,链表每两个一组交换了前后位置,然后再跟其他元素按照原有顺序连接。

在脉脉上看到一篇文章,StringBulider 为什么线程不安全,然后想了一下,确实不知道。

之前问string 相关问题,只了解了 string 不可变,stringbuffer 线程安全,stringbuilder 线程不安全。但却没有搞清楚为什么是不安全的,今天就去看了一下 stringbuilder 的源码,来了解一下原因。

首先来测试一下多线程下的不安全问题:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
public static void main(String[] args) {
    StringBuilder stringBuilder = new StringBuilder();

    for (int i = 0; i < 100000; i++) {
        new Thread(() -> stringBuilder.append("a")).start();
    }

    System.out.println(stringBuilder.length());

}

这个方法最终的理想结果应该是 100000,但是当我们多运行几次,发现他的结果出错了!结果变成了99999或者更小的数值。有时候甚至还抛出了数组越界异常(概率极小)。

整数反转—LeetCode7
2019 年 11 月 15 日

题目描述

给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。

示例 1:

输入: 123 输出: 321 示例 2:

输入: -123 输出: -321 示例 3:

输入: 120 输出: 21 注意:

假设我们的环境只能存储得下 32 位的有符号整数,则其数值范围为 [−231, 231 − 1]。请根据这个假设,如果反转后整数溢出那么就返回 0。

题目中给出了条件,我们只能存储32位有符号整数,如果溢出后则返回0,避免出现溢出错误

TreeMap源码学习
2019 年 11 月 12 日

之前看过了HashMap,LinkedHashMap的源码,这次来看一下TreeMap的源码。

从这个名字就能看出,TreeMap底层使用的是树来进行存储的。

变量

1
2
3
4
5
6
7
8
9
//比较器,用于左右子树的判断。
//正常情况下,左子树为 1,父节点为 2,右子树为 3。如果比较器设置 3<1<2。则左子树为3,父节点为 1,右子树为 2。
private final Comparator<? super K> comparator;
//根节点
private transient Entry<K,V> root;
//容量
private transient int size = 0;
//修改的次数,在迭代和序列化时用到
private transient int modCount = 0;

看一下 root 节点的数据结构:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
static final class Entry<K,V> implements Map.Entry<K,V> {
        K key;
        V value;
        Entry<K,V> left;
        Entry<K,V> right;
        Entry<K,V> parent;
        boolean color = BLACK;

	...
}

由于有一个color=BLACK属性,所以底层数据结构应该是红黑树