排序算法
冒泡排序
public static void bubbleSort(int[] arr){
int temp=0;
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr.length-1-i;j++)
if (arr[j]>arr[j+1]){
temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
}
}
选择排序
选择排序(select sorting)也是一种简单的排序方法。它的基本思想是:第一次从arr[0]arr[n-1]中选取最小值,与arr[0]交换,第二次从arr[1]arr[n-1]中选取最小值,与arr[1]交换,第三次从arr[2]arr[n-1]中选取最小值,与arr[2]交换,…,第i次从arr[i-1]arr[n-1]中选取最小值,与arr[i-1]交换,…, 第n-1次从arr[n-2]~arr[n-1]中选取最小值,与arr[n-2]交换,总共通过n-1次,得到一个按排序码从小到大排列的有序序列。
public static void selectSort(int[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
int minIndex = i;
int min = arr[i];
for (int j = i + 1; j < arr.length; j++) {
if (min > arr[j]) {
min = arr[j];
minIndex = j;
}
}
if (minIndex != i) {
arr[minIndex] = arr[i];
arr[i] = min;
}
}
插入排序
插入排序(Insertion Sorting)的基本思想是:把n个待排序的元素看成为一个有序表和一个无序表,开始时有序表中只包含一个元素,无序表中包含有n-1个元素,排序过程中每次从无序表中取出第一个元素,把它的排序码依次与有序表元素的排序码进行比较,将它插入到有序表中的适当位置,使之成为新的有序表。
public static void insertSort(int[] arr) {
int insertVal = 0;
int insertIndex = 0;
for(int i = 1; i < arr.length; i++) {
insertVal = arr[i];
insertIndex = i - 1;
while (insertIndex >= 0 && insertVal < arr[insertIndex]) {
arr[insertIndex + 1] = arr[insertIndex];
insertIndex--;
}
if(insertIndex + 1 != i) {
arr[insertIndex + 1] = insertVal;
}
}
希尔排序
希尔排序是希尔(Donald Shell)于1959年提出的一种排序算法。希尔排序也是一种插入排序,它是简单插入排序经过改进之后的一个更高效的版本,也称为缩小增量排序。
希尔排序法基本思想
希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止
public static void shellSort(int[] arr) {
int temp = 0;
int count = 0;
for (int gap = arr.length / 2; gap > 0; gap /= 2) {
for (int i = gap; i < arr.length; i++) {
for (int j = i - gap; j >= 0; j -= gap) {
if (arr[j] > arr[j + gap]) {
temp = arr[j];
arr[j] = arr[j + gap];
arr[j + gap] = temp;
}
}
}
}
快速排序
快速排序(Quicksort)是对冒泡排序的一种改进。基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列
public static void quickSort(int[] arr,int left, int right) {
int l = left;
int r = right;
int pivot = arr[(left + right) / 2];
int temp = 0;
while( l < r) {
while( arr[l] < pivot) {
l += 1;
}
while(arr[r] > pivot) {
r -= 1;
}
if( l >= r) {
break;
}
temp = arr[l];
arr[l] = arr[r];
arr[r] = temp;
if(arr[l] == pivot) {
r -= 1;
}
if(arr[r] == pivot) {
l += 1;
}
}
if (l == r) {
l += 1;
r -= 1;
}
if(left < r) {
quickSort(arr, left, r);
}
if(right > l) {
quickSort(arr, l, right);
}
}
并归排序
归并排序(MERGE-SORT)是利用归并的思想实现的排序方法,该算法采用经典的分治(divide-and-conquer)策略(分治法将问题分(divide)成一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之)
public static void mergeSort(int[] arr, int left, int right, int[] temp) {
if(left < right) {
int mid = (left + right) / 2;
mergeSort(arr, left, mid, temp);
mergeSort(arr, mid + 1, right, temp);
merge(arr, left, mid, right, temp);
}
}
public static void merge(int[] arr, int left, int mid, int right, int[] temp) {
int i = left;
int j = mid + 1;
int t = 0;
while (i <= mid && j <= right) {
if(arr[i] <= arr[j]) {
temp[t] = arr[i];
t += 1;
i += 1;
} else {
temp[t] = arr[j];
t += 1;
j += 1;
}
}
while( i <= mid) {
temp[t] = arr[i];
t += 1;
i += 1;
}
while( j <= right) {
temp[t] = arr[j];
t += 1;
j += 1;
}
t = 0;
int tempLeft = left;
while(tempLeft <= right) {
arr[tempLeft] = temp[t];
t += 1;
tempLeft += 1;
}
基数排序
基数排序(radix sort)属于“分配式排序”(distribution sort),又称“桶子法”(bucket sort)或bin sort,顾名思义,它是通过键值的各个位的值,将要排序的元素分配至某些“桶”中,达到排序的作用
基数排序法是属于稳定性的排序,基数排序法的是效率高的稳定性排序法
基数排序(Radix Sort)是桶排序的扩展
基数排序是1887年赫尔曼·何乐礼发明的。它是这样实现的:将整数按位数切割成不同的数字,然后按每个位数分别比较。
public static void radixSort(int[] arr) {
int max = arr[0];
for(int i = 1; i < arr.length; i++) {
if (arr[i] > max) {
max = arr[i];
}
}
int maxLength = (max + "").length();
int[][] bucket = new int[10][arr.length];
int[] bucketElementCounts = new int[10];
for(int i = 0 , n = 1; i < maxLength; i++, n *= 10) {
for(int j = 0; j < arr.length; j++) {
int digitOfElement = arr[j] / n % 10;
bucket[digitOfElement][bucketElementCounts[digitOfElement]] = arr[j];
bucketElementCounts[digitOfElement]++;
}
int index = 0;
for(int k = 0; k < bucketElementCounts.length; k++) {
if(bucketElementCounts[k] != 0) {
for(int l = 0; l < bucketElementCounts[k]; l++) {
arr[index++] = bucket[k][l];
}
}
bucketElementCounts[k] = 0;
}
}
堆排序
堆排序是利用堆这种数据结构而设计的一种排序算法,堆排序是一种选择排序,它的最坏,最好,平均时间复杂度均为O(nlogn),它也是不稳定排序。 堆是具有以下性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆,
大顶堆特点:arr[i] >= arr[2i+1] && arr[i] >= arr[2i+2] // i 对应第几个节点,i从0开始编号。注意 : 没有要求结点的左孩子的值和右孩子的值的大小关系。
每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。arr[i] <= arr[2i+1] && arr[i] <= arr[2i+2]
堆排序的基本思想是: 将待排序序列构造成一个大顶堆 此时,整个序列的最大值就是堆顶的根节点。 将其与末尾元素进行交换,此时末尾就为最大值。 然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列了。
public static void heapSort(int arr[]) {
int temp = 0;
System.out.println("堆排序!!");
for(int i = arr.length / 2 -1; i >=0; i--) {
adjustHeap(arr, i, arr.length);
}
for(int j = arr.length-1;j >0; j--) {
temp = arr[j];
arr[j] = arr[0];
arr[0] = temp;
adjustHeap(arr, 0, j);
}
}
public static void adjustHeap(int arr[], int i, int lenght) {
int temp = arr[i];
for(int k = i * 2 + 1; k < lenght; k = k * 2 + 1) {
if(k+1 < lenght && arr[k] < arr[k+1]) {
k++;
}
if(arr[k] > temp) {
arr[i] = arr[k];
i = k;
} else {
break;
}
}
arr[i] = temp;
}
查找算法
二分查找
public static int binarySearch(int[] arr, int left, int right, int findVal) {
if (left > right) {
return -1;
}
int mid = (left + right) / 2;
int midVal = arr[mid];
if (findVal > midVal) {
return binarySearch(arr, mid + 1, right, findVal);
} else if (findVal < midVal) {
return binarySearch(arr, left, mid - 1, findVal);
} else {
return mid;
}
}
差值查找
插值查找算法类似于二分查找,不同的是插值查找每次从自适应mid处开始查找
public static int insertValueSearch(int[] arr, int left, int right, int findVal) {
if (left > right || findVal < arr[0] || findVal > arr[arr.length - 1]) {
return -1;
}
int mid = left + (right - left) * (findVal - arr[left]) / (arr[right] - arr[left]);
int midVal = arr[mid];
if (findVal > midVal) {
return insertValueSearch(arr, mid + 1, right, findVal);
} else if (findVal < midVal) {
return insertValueSearch(arr, left, mid - 1, findVal);
} else {
return mid;
}
}
斐波那契查找
public static int[] fib(int maxSize) {
int[] f = new int[maxSize];
f[0] = 1;
f[1] = 1;
for (int i = 2; i < maxSize; i++) {
f[i] = f[i - 1] + f[i - 2];
}
return f;
}
public static int fibSearch(int[] a, int key) {
int low = 0;
int high = a.length - 1;
int k = 0;
int mid = 0;
int f[] = fib(maxSize);
while(high > f[k] - 1) {
k++;
}
int[] temp = Arrays.copyOf(a, f[k]);
for(int i = high + 1; i < temp.length; i++) {
temp[i] = a[high];
}
while (low <= high) {
mid = low + f[k - 1] - 1;
if(key < temp[mid]) {
high = mid - 1;
k--;
} else if ( key > temp[mid]) {
low = mid + 1;
k -= 2;
} else {
if(mid <= high) {
return mid;
} else {
return high;
}
}
}
return -1;
}
二叉树
二叉树遍历
class HeroNode {
private int no;
private String name;
private HeroNode left;
private HeroNode right;
public HeroNode(int no, String name) {
this.no = no;
this.name = name;
}
public void preOrder() {
System.out.println(this);
if(this.left != null) {
this.left.preOrder();
}
if(this.right != null) {
this.right.preOrder();
}
}
public void infixOrder() {
if(this.left != null) {
this.left.infixOrder();
}
System.out.println(this);
if(this.right != null) {
this.right.infixOrder();
}
}
public void postOrder() {
if(this.left != null) {
this.left.postOrder();
}
if(this.right != null) {
this.right.postOrder();
}
System.out.println(this);
}
public HeroNode preOrderSearch(int no) {
if(this.no == no) {
return this;
}
HeroNode resNode = null;
if(this.left != null) {
resNode = this.left.preOrderSearch(no);
}
if(resNode != null) {
return resNode;
}
if(this.right != null) {
resNode = this.right.preOrderSearch(no);
}
return resNode;
}
}
删除节点
public void delNode(int no) {
if(this.left != null && this.left.no == no) {
this.left = null;
return;
}
if(this.right != null && this.right.no == no) {
this.right = null;
return;
}
if(this.left != null) {
this.left.delNode(no);
}
if(this.right != null) {
this.right.delNode(no);
}
}
顺序存储二叉树
顺序二叉树通常只考虑完全二叉树 第n个元素的左子节点为 2 * n + 1 第n个元素的右子节点为 2 * n + 2 第n个元素的父节点为 (n-1) / 2
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fWGX8ZPZ-1657510180973)(D:\学习资料\img\1656551363202.png)]
class ArrBinaryTree {
private int[] arr;
public ArrBinaryTree(int[] arr) {
this.arr = arr;
}
public void preOrder() {
this.preOrder(0);
}
顺序储蓄二叉树的前序遍历
public void preOrder(int index) {
if(arr == null || arr.length == 0) {
System.out.println("数组为空,不能按照二叉树的前序遍历");
}
System.out.println(arr[index]);
if((index * 2 + 1) < arr.length) {
preOrder(2 * index + 1 );
}
if((index * 2 + 2) < arr.length) {
preOrder(2 * index + 2);
}
}
}
线索化二叉树
class ThreadedBinaryTree {
private HeroNode root;
private HeroNode pre = null;
public void setRoot(HeroNode root) {
this.root = root;
}
public void threadedNodes() {
this.threadedNodes(root);
}
public HeroNode preOrderSearch(int no) {
if(root != null) {
return root.preOrderSearch(no);
} else {
return null;
}
}
public HeroNode infixOrderSearch(int no) {
if(root != null) {
return root.infixOrderSearch(no);
}else {
return null;
}
}
public HeroNode postOrderSearch(int no) {
if(root != null) {
return this.root.postOrderSearch(no);
}else {
return null;
}
}
}
public void preOrder() {
if(this.root != null) {
this.root.preOrder();
}else {
System.out.println("二叉树为空,无法遍历");
}
}
public void infixOrder() {
if(this.root != null) {
this.root.infixOrder();
}else {
System.out.println("二叉树为空,无法遍历");
}
}
中序线索化二叉树
public void threadedNodes(HeroNode node) {
if(node == null) {
return;
}
threadedNodes(node.getLeft());
if(node.getLeft() == null) {
node.setLeft(pre);
node.setLeftType(1);
}
if (pre != null && pre.getRight() == null) {
pre.setRight(node);
pre.setRightType(1);
}
pre = node;
threadedNodes(node.getRight());
}
中序线索化二叉树遍历
public void threadedList() {
HeroNode node = root;
while(node != null) {
while(node.getLeftType() == 0) {
node = node.getLeft();
}
System.out.println(node);
while(node.getRightType() == 1) {
node = node.getRight();
System.out.println(node);
}
node = node.getRight();
}
}
class HeroNode {
private int no;
private String name;
private HeroNode left;
private HeroNode right;
private int leftType;
private int rightType;
public int getLeftType() {
return leftType;
}
public void setLeftType(int leftType) {
this.leftType = leftType;
}
public int getRightType() {
return rightType;
}
public void setRightType(int rightType) {
this.rightType = rightType;
}
public HeroNode(int no, String name) {
this.no = no;
this.name = name;
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public HeroNode getLeft() {
return left;
}
public void setLeft(HeroNode left) {
this.left = left;
}
public HeroNode getRight() {
return right;
}
public void setRight(HeroNode right) {
this.right = right;
}
@Override
public String toString() {
return "HeroNode [no=" + no + ", name=" + name + "]";
}
public void delNode(int no) {
if(this.left != null && this.left.no == no) {
this.left = null;
return;
}
if(this.right != null && this.right.no == no) {
this.right = null;
return;
}
if(this.left != null) {
this.left.delNode(no);
}
if(this.right != null) {
this.right.delNode(no);
}
}
public void preOrder() {
System.out.println(this);
if(this.left != null) {
this.left.preOrder();
}
if(this.right != null) {
this.right.preOrder();
}
}
public void infixOrder() {
if(this.left != null) {
this.left.infixOrder();
}
System.out.println(this);
if(this.right != null) {
this.right.infixOrder();
}
}
public void postOrder() {
if(this.left != null) {
this.left.postOrder();
}
if(this.right != null) {
this.right.postOrder();
}
System.out.println(this);
}
public HeroNode preOrderSearch(int no) {
System.out.println("进入前序遍历");
if(this.no == no) {
return this;
}
HeroNode resNode = null;
if(this.left != null) {
resNode = this.left.preOrderSearch(no);
}
if(resNode != null) {
return resNode;
}
if(this.right != null) {
resNode = this.right.preOrderSearch(no);
}
return resNode;
}
public HeroNode infixOrderSearch(int no) {
HeroNode resNode = null;
if(this.left != null) {
resNode = this.left.infixOrderSearch(no);
}
if(resNode != null) {
return resNode;
}
System.out.println("进入中序查找");
if(this.no == no) {
return this;
}
if(this.right != null) {
resNode = this.right.infixOrderSearch(no);
}
return resNode;
}
public HeroNode postOrderSearch(int no) {
HeroNode resNode = null;
if(this.left != null) {
resNode = this.left.postOrderSearch(no);
}
if(resNode != null) {
return resNode;
}
if(this.right != null) {
resNode = this.right.postOrderSearch(no);
}
if(resNode != null) {
return resNode;
}
System.out.println("进入后序查找");
if(this.no == no) {
return this;
}
return resNode;
}
二叉排序树
二叉排序树:BST: (Binary Sort(Search) Tree), 对于二叉排序树的任何一个非叶子节点,要求左子节点的值比当前节点的值小,右子节点的值比当前节点的值大。 特别说明:如果有相同的值,可以将该节点放在左子节点或右子节点
节点代码
class Node {
int value;
Node left;
Node right;
public Node(int value) {
this.value = value;
}
public Node search(int value) {
if(value == this.value) {
return this;
} else if(value < this.value) {
if(this.left == null) {
return null;
}
return this.left.search(value);
} else {
if(this.right == null) {
return null;
}
return this.right.search(value);
}
}
public Node searchParent(int value) {
if((this.left != null && this.left.value == value) ||
(this.right != null && this.right.value == value)) {
return this;
} else {
if(value < this.value && this.left != null) {
return this.left.searchParent(value);
} else if (value >= this.value && this.right != null) {
return this.right.searchParent(value);
} else {
return null;
}
}
}
public void add(Node node) {
if(node == null) {
return;
}
if(node.value < this.value) {
if(this.left == null) {
this.left = node;
} else {
this.left.add(node);
}
} else {
if(this.right == null) {
this.right = node;
} else {
this.right.add(node);
}
}
}
public void infixOrder() {
if(this.left != null) {
this.left.infixOrder();
}
System.out.println(this);
if(this.right != null) {
this.right.infixOrder();
}
}
}
class BinarySortTree {
private Node root;
public Node getRoot() {
return root;
}
public Node search(int value) {
if(root == null) {
return null;
} else {
return root.search(value);
}
}
public Node searchParent(int value) {
if(root == null) {
return null;
} else {
return root.searchParent(value);
}
}
public int delRightTreeMin(Node node) {
Node target = node;
while(target.left != null) {
target = target.left;
}
delNode(target.value);
return target.value;
}
public void delNode(int value) {
if(root == null) {
return;
}else {
Node targetNode = search(value);
if(targetNode == null) {
return;
}
if(root.left == null && root.right == null) {
root = null;
return;
}
Node parent = searchParent(value);
if(targetNode.left == null && targetNode.right == null) {
if(parent.left != null && parent.left.value == value) {
parent.left = null;
} else if (parent.right != null && parent.right.value == value) {
parent.right = null;
}
} else if (targetNode.left != null && targetNode.right != null) {
int minVal = delRightTreeMin(targetNode.right);
targetNode.value = minVal;
} else {
if(targetNode.left != null) {
if(parent != null) {
if(parent.left.value == value) {
parent.left = targetNode.left;
} else {
parent.right = targetNode.left;
}
} else {
root = targetNode.left;
}
} else {
if(parent != null) {
if(parent.left.value == value) {
parent.left = targetNode.right;
} else {
parent.right = targetNode.right;
}
} else {
root = targetNode.right;
}
}
}
}
}
平衡AVL树,平衡二叉排序树
给你一个数列{1,2,3,4,5,6},要求创建一颗二叉排序树(BST), 并分析问题所在.
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vFD2OfNs-1657510180976)(D:\学习资料\img\1656553214080.png)]
平衡二叉树也叫平衡二叉搜索树(Self-balancing binary search tree)又被称为AVL树, 可以保证查询效率较高。 具有以下特点:它是一 棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。平衡二叉树的常用实现方法有红黑树、AVL、替罪羊树、Treap、伸展树等。
Node节点
class Node {
int value;
Node left;
Node right;
public Node(int value) {
this.value = value;
}
public int leftHeight() {
if (left == null) {
return 0;
}
return left.height();
}
public int rightHeight() {
if (right == null) {
return 0;
}
return right.height();
}
public int height() {
return Math.max(left == null ? 0 : left.height(), right == null ? 0 : right.height()) + 1;
}
private void leftRotate() {
Node newNode = new Node(value);
newNode.left = left;
newNode.right = right.left;
value = right.value;
right = right.right;
left = newNode;
}
private void rightRotate() {
Node newNode = new Node(value);
newNode.right = right;
newNode.left = left.right;
value = left.value;
left = left.left;
right = newNode;
}
public Node search(int value) {
if (value == this.value) {
return this;
} else if (value < this.value) {
if (this.left == null) {
return null;
}
return this.left.search(value);
} else {
if (this.right == null) {
return null;
}
return this.right.search(value);
}
}
public Node searchParent(int value) {
if ((this.left != null && this.left.value == value) || (this.right != null && this.right.value == value)) {
return this;
} else {
if (value < this.value && this.left != null) {
return this.left.searchParent(value);
} else if (value >= this.value && this.right != null) {
return this.right.searchParent(value);
} else {
return null;
}
}
}
@Override
public String toString() {
return "Node [value=" + value + "]";
}
public void add(Node node) {
if (node == null) {
return;
}
if (node.value < this.value) {
if (this.left == null) {
this.left = node;
} else {
this.left.add(node);
}
} else {
if (this.right == null) {
this.right = node;
} else {
this.right.add(node);
}
}
if(rightHeight() - leftHeight() > 1) {
if(right != null && right.leftHeight() > right.rightHeight()) {
right.rightRotate();
leftRotate();
} else {
leftRotate();
}
return ;
}
if(leftHeight() - rightHeight() > 1) {
if(left != null && left.rightHeight() > left.leftHeight()) {
left.leftRotate();
rightRotate();
} else {
rightRotate();
}
}
}
public void infixOrder() {
if (this.left != null) {
this.left.infixOrder();
}
System.out.println(this);
if (this.right != null) {
this.right.infixOrder();
}
}
}
AVl树
class AVLTree {
private Node root;
public Node getRoot() {
return root;
}
public Node search(int value) {
if (root == null) {
return null;
} else {
return root.search(value);
}
}
public Node searchParent(int value) {
if (root == null) {
return null;
} else {
return root.searchParent(value);
}
}
public int delRightTreeMin(Node node) {
Node target = node;
while (target.left != null) {
target = target.left;
}
delNode(target.value);
return target.value;
}
public void delNode(int value) {
if (root == null) {
return;
} else {
Node targetNode = search(value);
if (targetNode == null) {
return;
}
if (root.left == null && root.right == null) {
root = null;
return;
}
Node parent = searchParent(value);
if (targetNode.left == null && targetNode.right == null) {
if (parent.left != null && parent.left.value == value) {
parent.left = null;
} else if (parent.right != null && parent.right.value == value) {
parent.right = null;
}
} else if (targetNode.left != null && targetNode.right != null) {
int minVal = delRightTreeMin(targetNode.right);
targetNode.value = minVal;
} else {
if (targetNode.left != null) {
if (parent != null) {
if (parent.left.value == value) {
parent.left = targetNode.left;
} else {
parent.right = targetNode.left;
}
} else {
root = targetNode.left;
}
} else {
if (parent != null) {
if (parent.left.value == value) {
parent.left = targetNode.right;
} else {
parent.right = targetNode.right;
}
} else {
root = targetNode.right;
}
}
}
}
}
public void add(Node node) {
if (root == null) {
root = node;
} else {
root.add(node);
}
}
public void infixOrder() {
if (root != null) {
root.infixOrder();
} else {
System.out.println("二叉排序树为空,不能遍历");
}
}
}
2-3树,B树,B+树
2-3树的所有叶子节点都在同一层.(只要是B树都满足这个条件) 有两个子节点的节点叫二节点,二节点要么没有子节点,要么有两个子节点.
有三个子节点的节点叫三节点,三节点要么没有子节点,要么有三个子节点. 2-3树是由二节点和三节点构成的树。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AGhLZJbG-1657510180979)(C:\Users\Hao\AppData\Roaming\Typora\typora-user-images\1656554264265.png)]
B树的阶:节点的最多子节点个数。比如2-3树的阶是3,2-3-4树的阶是4 B-树的搜索,从根结点开始,对结点内的关键字(有序)序列进行二分查找,如果命中则结束,否则进入查询关键字所属范围的儿子结点;重复,直到所对应的儿子指针为空,或已经是叶子结点
关键字集合分布在整颗树中, 即叶子节点和非叶子节点都存放数据. 搜索有可能在非叶子结点结束 其搜索性能等价于在关键字全集内做一次二分查找
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rM3cpb9r-1657510180980)(D:\学习资料\img\1656554351835.png)]
B+树是B树的变体,也是一种多路搜索树。B+树的搜索与B树也基本相同,区别是B+树只有达到叶子结点才命中(B树可以在非叶子结点命中),其性能也等价于在关键字全集做一次二分查找 所有关键字都出现在叶子结点的链表中(即数据只能在叶子节点【也叫稠密索引】),且链表中的关键字(数据)恰好是有序的。 不可能在非叶子结点命中 非叶子结点相当于是叶子结点的索引(稀疏索引),叶子结点相当于是存储(关键字)数据的数据层 更适合文件索引系统 B树和B+树各有自己的应用场景,不能说B+树完全比B树好,反之亦然.
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0qJtC27l-1657510180981)(D:\学习资料\img\1656554391391.png)]
图的深度优先和广度优先
package com.atguigu.graph;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
public class Graph {
private ArrayList<String> vertexList;
private int[][] edges;
private int numOfEdges;
private boolean[] isVisited;
public Graph(int n) {
edges = new int[n][n];
vertexList = new ArrayList<String>(n);
numOfEdges = 0;
}
public int getFirstNeighbor(int index) {
for(int j = 0; j < vertexList.size(); j++) {
if(edges[index][j] > 0) {
return j;
}
}
return -1;
}
public int getNextNeighbor(int v1, int v2) {
for(int j = v2 + 1; j < vertexList.size(); j++) {
if(edges[v1][j] > 0) {
return j;
}
}
return -1;
}
private void dfs(boolean[] isVisited, int i) {
System.out.print(getValueByIndex(i) + "->");
isVisited[i] = true;
int w = getFirstNeighbor(i);
while(w != -1) {
if(!isVisited[w]) {
dfs(isVisited, w);
}
w = getNextNeighbor(i, w);
}
}
public void dfs() {
isVisited = new boolean[vertexList.size()];
for(int i = 0; i < getNumOfVertex(); i++) {
if(!isVisited[i]) {
dfs(isVisited, i);
}
}
}
private void bfs(boolean[] isVisited, int i) {
int u ;
int w ;
LinkedList queue = new LinkedList();
System.out.print(getValueByIndex(i) + "=>");
isVisited[i] = true;
queue.addLast(i);
while( !queue.isEmpty()) {
u = (Integer)queue.removeFirst();
w = getFirstNeighbor(u);
while(w != -1) {
if(!isVisited[w]) {
System.out.print(getValueByIndex(w) + "=>");
isVisited[w] = true;
queue.addLast(w);
}
w = getNextNeighbor(u, w);
}
}
}
public void bfs() {
isVisited = new boolean[vertexList.size()];
for(int i = 0; i < getNumOfVertex(); i++) {
if(!isVisited[i]) {
bfs(isVisited, i);
}
}
}
public int getNumOfVertex() {
return vertexList.size();
}
public void showGraph() {
for(int[] link : edges) {
System.err.println(Arrays.toString(link));
}
}
public int getNumOfEdges() {
return numOfEdges;
}
public String getValueByIndex(int i) {
return vertexList.get(i);
}
public int getWeight(int v1, int v2) {
return edges[v1][v2];
}
public void insertVertex(String vertex) {
vertexList.add(vertex);
}
public void insertEdge(int v1, int v2, int weight) {
edges[v1][v2] = weight;
edges[v2][v1] = weight;
numOfEdges++;
}
}
计算系列
杨辉三角
给定一个非负整数 *numRows ,*生成「杨辉三角」的前 numRows 行。
在「杨辉三角」中,每个数是它左上方和右上方的数的和。
class Solution {
private List<List<Integer>> ans;
private List<Integer> curans;
public List<List<Integer>> generate(int numRows) {
ans=new ArrayList<List<Integer>>();
curans=new ArrayList<>();
int[][] ansgrid =new int[numRows][numRows];
for (int i = 0; i <ansgrid.length ; i++) {
for (int j = 0; j <ansgrid[0].length ; j++) {
if (j==0||i==j){
ansgrid[i][j]=1;
continue;
}
ansgrid[i][j]=0;
}
}
for (int i = 2; i <ansgrid.length ; i++) {
for (int j = 1; j <i ; j++) {
ansgrid[i][j]=ansgrid[i-1][j-1]+ansgrid[i-1][j];
}
}
for (int i = 0; i <ansgrid.length ; i++) {
curans=new ArrayList<>();
for (int j = 0; j <=i ; j++) {
curans.add(ansgrid[i][j]);
}
ans.add(curans);
}
return ans;
}
}
加一
给定一个由 整数 组成的 非空 数组所表示的非负整数,在该数的基础上加一。
最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。
你可以假设除了整数 0 之外,这个整数不会以零开头。
digits = [1,2,3]
输出:[1,2,4]
解释:输入数组表示数字 123。
class Solution {
public int[] plusOne(int[] digits) {
if (digits[digits.length-1]<=8){
digits[digits.length-1]=digits[digits.length-1]+1;
return digits;
}
if(digits.length==1){
int[] ans = new int[digits.length+1];
ans[0]=1;
return ans;
}
digits[digits.length-1]=0;
int count=1;
for (int i = digits.length-2; i >=0 ; i--) {
int curval=digits[i]+count;
if (i==0&&curval==10){
int[] ans = new int[digits.length+1];
ans[0]=1;
return ans;
}
if(curval==10){
count=1;
digits[i]=0;
continue;
}
digits[i]=curval;
break;
}
return digits;
}
}
两数之和
给定一个整数数组 nums 和一个整数目标值 target ,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
nums = [2,7,11,15], target = 9
输出:[0,1]
class Solution {
public int[] twoSum(int[] nums, int target) {
HashMap<Integer, Integer> hashtable = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
if (hashtable.containsKey(target - nums[i])) {
int start = hashtable.get(target - nums[i]);
int end = i;
int ans[]={start,end};
return ans;
}
hashtable.put(nums[i], i);
}
return new int[0];
}
}
两数相加
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
int plus = 0;
int val = l1.val + l2.val;
plus = val / 10;
ListNode rs = new ListNode(val % 10);
ListNode p1 = l1.next, p2 = l2.next, cur = rs;
while (p1 != null || p2 != null || plus != 0) {
val = 0;
if (p1 != null) {
val += p1.val;
}
if (p2 != null) {
val += p2.val;
}
val = plus + val;
plus = val / 10;
cur.next = new ListNode(val % 10);
if (p1 != null) {
p1 = p1.next;
}
if (p2 != null) {
p2 = p2.next;
}
cur = cur.next;
}
return rs;
}
}
三数之和
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> ans = new ArrayList();
int len = nums.length;
if(nums == null || len < 3) {
return ans;
}
Arrays.sort(nums);
for (int i = 0; i < len ; i++) {
if(nums[i] > 0) break;
if(i > 0 && nums[i] == nums[i-1]){
continue;
}
int L = i+1;
int R = len-1;
while(L < R){
int sum = nums[i] + nums[L] + nums[R];
if(sum == 0){
ans.add(Arrays.asList(nums[i],nums[L],nums[R]));
while (L<R && nums[L] == nums[L+1]){
L++;
}
while (L<R && nums[R] == nums[R-1]) {
R--;
}
L++;
R--;
}
else if (sum < 0){
L++;
}
else if (sum > 0) {
R--;
}
}
}
return ans;
}
}
四数之和
给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复)
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> ans = new ArrayList<>();
Arrays.sort(nums);
if (nums.length<4){
return ans;
}
for (int a = 0; a <nums.length-3 ; a++) {
if (a>0&&nums[a]==nums[a-1]){
continue;
}
for (int b = a+1; b <nums.length-2 ; b++) {
if (b>a+1&&nums[b]==nums[b-1]){
continue;
}
int left=b+1;
int right=nums.length-1;
while (left<right){
if (nums[a]+nums[b]+nums[left]+nums[right]<target){
left++;
}else if (nums[a]+nums[b]+nums[left]+nums[right]>target){
right--;
}else {
List<Integer> curans = new ArrayList<>();
curans.add(nums[a]);
curans.add(nums[b]);
curans.add(nums[left]);
curans.add(nums[right]);
ans.add(curans);
while (left<right&&nums[left]==nums[left+1]){
left++;
}
while (left<right&&nums[right]==nums[right-1]){
right--;
}
left++;
right--;
}
}
}
}
return ans;
}
}
两数相除
class Solution {
//利用递归,利用加法每次除到不能再相除
public int divide(int dividend, int divisor) {
if(dividend == 0) return 0;
if(dividend == Integer.MIN_VALUE && divisor == -1) return Integer.MAX_VALUE;
int sign = 1;
if((dividend > 0 && divisor < 0) || (dividend < 0 && divisor > 0))
sign = -1;
//Integer.MAX Integer.MIN 盛
dividend = dividend > 0 ? -dividend : dividend;
divisor = divisor > 0 ? -divisor : divisor;
return sign * helper(dividend, divisor);
}
/*
坚定不移的相信, 这个函数可以帮你完成任务
*/
public int helper(int a, int b){
//a = -1, b = -5
if(a >= b) return a > b ? 0 : 1;
int count = 1;
int res = 0;
int tb = b;
while(a <= tb && tb < 0){
a -= tb;
res += count;
tb += tb;
count += count;
}
return res + helper(a, b);
}
}
字符串
简化路径
给你一个字符串 path ,表示指向某一文件或目录的 Unix 风格 绝对路径 (以 ‘/’ 开头),请你将其转化为更加简洁的规范路径。
在 Unix 风格的文件系统中,一个点(.)表示当前目录本身;此外,两个点 (…) 表示将目录切换到上一级(指向父目录);两者都可以是复杂相对路径的组成部分。任意多个连续的斜杠(即,‘//’)都被视为单个斜杠 ‘/’ 。 对于此问题,任何其他格式的点(例如,‘…’)均被视为文件/目录名称。
请注意,返回的 规范路径 必须遵循下述格式:
始终以斜杠 ‘/’ 开头。 两个目录名之间必须只有一个斜杠 ‘/’ 。 最后一个目录名(如果存在)不能 以 ‘/’ 结尾。 此外,路径仅包含从根目录到目标文件或目录的路径上的目录(即,不含 ‘.’ 或 ‘…’)。 返回简化后得到的 规范路径
输入:path = "/home/"
输出:"/home"
解释:注意,最后一个目录名后面没有斜杠。
class Solution {
public String simplifyPath(String path) {
Stack<String> ansstack = new Stack<>();
String[] split = path.split("/");
StringBuilder ansstr = new StringBuilder();
for (int i = 0; i <split.length ; i++) {
if (!"..".contains(split[i])){
ansstack.push(split[i]);
}
if (!ansstack.isEmpty()&&split[i].equals("..")){
ansstack.pop();
}
}
for (int i = 0; i <ansstack.size() ; i++) {
ansstr.append("/"+ansstack.get(i));
}
if (ansstr.length()==0){
return "/";
}
return ansstr.toString();
}
}
字母异位词分组
给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。
字母异位词 是由重新排列源单词的字母得到的一个新单词,所有源单词中的字母通常恰好只用一次。
class Solution {
public List<List<String>> groupAnagrams(String[] strs) {
Map<String, List<String>> map = new HashMap<String, List<String>>();
for (String str : strs) {
char[] array = str.toCharArray();
Arrays.sort(array);
String key = new String(array);
List<String> list = map.getOrDefault(key, new ArrayList<String>());
list.add(str);
map.put(key, list);
}
return new ArrayList<List<String>>(map.values());
}
}
无重复最长子串
给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
利用滑动窗口,在窗口中维护不重复子串,如果出现重复,从左边探出直至,没有重复,
class Solution {
public int lengthOfLongestSubstring(String s) {
HashSet<Character> tempset = new HashSet<>();
int endindex=-1;
int ans=0;
for (int i = 0; i <s.length() ; i++) {
if (i!=0){
tempset.remove(s.charAt(i-1));
}
while (endindex+1<s.length() && !tempset.contains(s.charAt(endindex+1))){
tempset.add(s.charAt(endindex+1));
endindex++;
}
ans=Math.max(ans,endindex-i+1);
}
return ans;
}
}
验证回文串
给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写
class Solution {
public boolean isPalindrome(String s) {
char[] schars = s.toCharArray();
StringBuilder strgood = new StringBuilder();
for (int i = 0; i <schars.length ; i++) {
if (Character.isLetterOrDigit(schars[i])) {
strgood.append(Character.toLowerCase(schars[i]));
}
}
char[] check = strgood.toString().toCharArray();
int left=0;
int right=check.length-1;
while (left<right){
if (check[left]!=check[right]){
return false;
}
left++;
right--;
}
return true;
}
}
最长回文子串
我们用一个 boolean dp[l][r] 表示字符串从 i 到 j 这段是否为回文。试想如果 dp[l][r]=true,我们要判断 dp[l-1][r+1] 是否为回文。只需要判断字符串在(l-1)和(r+1)两个位置是否为相同的字符,是不是减少了很多重复计算。
进入正题,动态规划关键是找到初始状态和状态转移方程。
初始状态,l=r 时,此时 dp[l][r]=true。
状态转移方程,dp[l][r]=true 并且(l-1)和(r+1)两个位置为相同的字符,此时 dp[l-1][r+1]=true。
public String longestPalindrome(String s) {
if (s == null || s.length() < 2) {
return s;
}
int strLen = s.length();
int maxStart = 0;
int maxEnd = 0;
int maxLen = 1;
boolean[][] dp = new boolean[strLen][strLen];
for (int r = 1; r < strLen; r++) {
for (int l = 0; l < r; l++) {
if (s.charAt(l) == s.charAt(r) && (r - l <= 2 || dp[l + 1][r - 1])) {
dp[l][r] = true;
if (r - l + 1 > maxLen) {
maxLen = r - l + 1;
maxStart = l;
maxEnd = r;
}
}
}
}
return s.substring(maxStart, maxEnd + 1);
}
链表
环形链表
给你一个链表的头节点 head ,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。
如果链表中存在环 ,则返回 true 。 否则,返回 false 。
public class Solution {
public boolean hasCycle(ListNode head) {
HashSet<ListNode> check = new HashSet<>();
ListNode index = head;
while (index!=null){
if (check.contains(index)){
return true;
}
check.add(index);
index=index.next;
}
return false;
}
}
环形链表2返回节点
给定一个链表的头节点 ?head?,返回链表开始入环的第一个节点。?如果链表无环,则返回?null。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
不允许修改 链表。
public class Solution {
public ListNode detectCycle(ListNode head) {
HashSet<ListNode> check = new HashSet<>();
ListNode index = head;
while (index!=null){
if (check.contains(index)){
return index;
}
check.add(index);
index=index.next;
}
return null;
}
}
重排链表、、
给定一个单链表 L 的头节点 head ,单链表 L 表示为:
L0 → L1 → … → Ln - 1 → Ln 请将其重新排列后变为:
L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → … 不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
class Solution {
public void reorderList(ListNode head) {
ArrayList<ListNode> help = new ArrayList<>();
ListNode index = head;
while (index!=null){
help.add(index);
index=index.next;
}
int left=0;
int right=help.size()-1;
while (left<right){
ListNode startNode = help.get(left);
ListNode endNode = help.get(right);
endNode.next=startNode.next;
startNode.next=endNode;
left++;
right--;
}
help.get(left).next=null;
}
}
反转链表
给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 。
class Solution {
public ListNode reverseBetween(ListNode head, int left, int right) {
ListNode leftinde=head;
ListNode rightindex=head;
int conut=1;
while (conut<left){
leftinde=leftinde.next;
conut++;
}
conut=(right+1-left)/2;
int index=right-left;
while (conut>0){
ListNode curindex=leftinde;
int temp=0;
while (temp!=index){
temp++;
curindex= curindex.next;
}
int tempval=curindex.val;
curindex.val=leftinde.val;
leftinde.val=tempval;
leftinde=leftinde.next;
index=index-2;
conut--;
}
return head;
}
}
分隔链表
给你一个链表的头节点 head 和一个特定值 x ,请你对链表进行分隔,使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。
你应当 保留 两个分区中每个节点的初始相对位置。
class Solution {
public ListNode partition(ListNode head, int x) {
ListNode small = new ListNode(0);
ListNode smallHead = small;
ListNode large = new ListNode(0);
ListNode largeHead = large;
while (head != null) {
if (head.val < x) {
small.next = head;
small = small.next;
} else {
large.next = head;
large = large.next;
}
head = head.next;
}
large.next = null;
small.next = largeHead.next;
return smallHead.next;
}
}
删除排序链表中的重复元素 II
给定一个已排序的链表的头 head , 删除原始链表中所有重复数字的节点,只留下不同的数字 。返回 已排序的链表
输入:head = [1,2,3,3,4,4,5]
输出:[1,2,5]
class Solution {
public ListNode deleteDuplicates(ListNode head) {
if (head == null) {
return head;
}
ListNode dummy = new ListNode(0, head);
ListNode cur = dummy;
while (cur.next != null && cur.next.next != null) {
if (cur.next.val == cur.next.next.val) {
int x = cur.next.val;
while (cur.next != null && cur.next.val == x) {
cur.next = cur.next.next;
}
} else {
cur = cur.next;
}
}
return dummy.next;
}
}
旋转链表
给你一个链表的头节点 head ,旋转链表,将链表每个节点向右移动 k 个位置。 ‘
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9cCoj1F8-1657510180983)(D:\学习资料\img\1657198007333.png)]
class Solution {
public ListNode rotateRight(ListNode head, int k) {
if(head==null){return null;}
int count = 0;
ListNode index = head;
while (index.next != null) {
count = count + 1;
index = index.next;
}
count = count + 1;
System.out.println(count);
if(count==1){return head;}
int location = k % count;
System.out.println(location);
index = head;
while (true){
if (index.next==null){
index.next=head;
break;
}
index=index.next;
}
int reverse=(count+1-location)-1;
int key=1;
index=head;
ListNode ans=null;
while (key<=count){
if (key==reverse){
ans=index.next;
index.next=null;
return ans;
}
key++;
index=index.next;
}
return ans;
}
}
删除链表倒数第N个节点
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
int size=1;
ListNode curentnode=head;
while (curentnode.next!=null){
curentnode = curentnode.next;
size++;
}
int zhengshu=size+1-n;
if (zhengshu==1){
head=head.next;
return head;
}
ListNode preNode=head;
curentnode=head.next;
int count=2;
while (count<zhengshu){
preNode = preNode.next;
curentnode = curentnode.next;
count++;
}
preNode.next=curentnode.next;
return head;
}
}
合并两个有序链表
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
if (l1==null){
return l2;
}
if (l2==null){
return l1;
}
if (l1.val<l2.val){
l1.next=mergeTwoLists(l1.next,l2);
return l1;
}else {
l2.next=mergeTwoLists(l1,l2.next);
return l2;
}
}
}
两两交换料表中的节点
class Solution {
public ListNode swapPairs(ListNode head) {
if (head==null||head.next==null) {
return head;
}
ListNode next=head.next;
head.next=swapPairs(next.next);
next.next=head;
return next;
}
}
二叉树
填充每一个节点的下一个右侧节点指针
给定一个 完美二叉树 ,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下:
struct Node { int val; Node *left; Node *right; Node *next; } 填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ps9wzHJp-1657510180984)(D:\学习资料\img\1657289295908.png)]
class Solution {
public Node connect(Node root) {
if(root==null)return root;
ArrayDeque<Node> curnodes=new ArrayDeque<>();
curnodes.add(root);
while (!curnodes.isEmpty()){
int size=curnodes.size();
ArrayList<Node> nodes = new ArrayList<>();
for (int i = 0; i <size ; i++) {
Node curnode = curnodes.remove();
nodes.add(curnode);
if (curnode.left!=null){
curnodes.add(curnode.left);
}
if (curnode.right!=null){
curnodes.add(curnode.right);
}
}
for (int i = 1; i <nodes.size() ; i++) {
Node pre = nodes.get(i - 1);
Node cur = nodes.get(i);
pre.next=cur;
}
}
return root;
}
}
填充每一个节点的下一个右侧节点指针2
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-M9wB04yi-1657510180985)(D:\学习资料\img\1657289489719.png)]
class Solution {
public Node connect(Node root) {
if(root==null)return root;
ArrayDeque<Node> curnodes=new ArrayDeque<>();
curnodes.add(root);
while (!curnodes.isEmpty()){
int size=curnodes.size();
ArrayList<Node> nodes = new ArrayList<>();
for (int i = 0; i <size ; i++) {
Node curnode = curnodes.remove();
nodes.add(curnode);
if (curnode.left!=null){
curnodes.add(curnode.left);
}
if (curnode.right!=null){
curnodes.add(curnode.right);
}
}
for (int i = 1; i <nodes.size() ; i++) {
Node pre = nodes.get(i - 1);
Node cur = nodes.get(i);
pre.next=cur;
}
}
return root;
}
}
二叉树展开为链表
给你二叉树的根结点 root ,请你将它展开为一个单链表:
展开后的单链表应该同样使用 TreeNode ,其中 right 子指针指向链表中下一个结点,而左子指针始终为 null 。 展开后的单链表应该与二叉树 先序遍历 顺序相同。
class Solution {
public void flatten(TreeNode root) {
List<TreeNode> list = new ArrayList<TreeNode>();
preorderTraversal(root, list);
int size = list.size();
for (int i = 1; i < size; i++) {
TreeNode prev = list.get(i - 1), curr = list.get(i);
prev.left = null;
prev.right = curr;
}
}
public void preorderTraversal(TreeNode root, List<TreeNode> list) {
if (root != null) {
list.add(root);
preorderTraversal(root.left, list);
preorderTraversal(root.right, list);
}
}
}
二叉树层序遍历
给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
ArrayList<List<Integer>> ans = new ArrayList<>();
ArrayDeque<TreeNode> curNodes = new ArrayDeque<TreeNode>();
if(root==null){
return ans;
}
curNodes.add(root);
while (!curNodes.isEmpty()){
ArrayList<Integer> temp = new ArrayList<>();
int cursize=curNodes.size();
for (int i = 0; i <cursize ; i++) {
TreeNode curnode = curNodes.remove();
temp.add(curnode.val);
if (curnode.left!=null){
curNodes.add(curnode.left);
}
if (curnode.right!=null){
curNodes.add(curnode.right);
}
}
ans.add(temp);
}
return ans;
}
}
二叉树的层序遍历自底向上
class Solution {
public List<List<Integer>> levelOrderBottom(TreeNode root) {
LinkedList<List<Integer>> ans = new LinkedList<>();
if (root==null){
return ans;
}
ArrayDeque<TreeNode> curnode = new ArrayDeque<>();
curnode.add(root);
while (!curnode.isEmpty()){
int size=curnode.size();
ArrayList<Integer> curans = new ArrayList<>();
for (int i = 0; i <size ; i++) {
TreeNode remove = curnode.remove();
curans.add(remove.val);
if (remove.left!=null){
curnode.add(remove.left);
}
if (remove.right!=null){
curnode.add(remove.right);
}
}
ans.addFirst(curans);
}
return new ArrayList<List<Integer>>(ans);
}
}
将有序数组转换为二叉搜索树
给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵 高度平衡 二叉搜索树。
class Solution {
public TreeNode sortedArrayToBST(int[] nums) {
return dfs(nums,0,nums.length-1);
}
private TreeNode dfs(int[] nums, int start, int end) {
if (start>end){
return null;
}
int mid=(start+end)/2;
TreeNode root = new TreeNode(nums[mid]);
root.left=dfs(nums,start,mid-1);
root.right=dfs(nums,mid+1,end);
return root;
}
}
将有序链表转换为二叉搜索树
class Solution {
public TreeNode sortedListToBST(ListNode head) {
if (head==null){
return null;
}
if (head.next == null) {
return new TreeNode(head.val);
}
ListNode fast=head;
ListNode slow=head;
ListNode pre=null;
while (fast!=null&&fast.next!=null){
pre=slow;
fast=fast.next.next;
slow=slow.next;
}
TreeNode root = new TreeNode(slow.val);
pre.next=null;
root.left=sortedListToBST(head);
root.right=sortedListToBST(slow.next);
return root;
}
}
判断是否平衡二叉树
class Solution {
public boolean isBalanced(TreeNode root) {
if(root == null) return true;
Stack<TreeNode> stack = new Stack<>();
TreeNode pre = null;
while(root != null || !stack.isEmpty()) {
if(root != null) {
stack.push(root);
root = root.left;
}else {
TreeNode inNode = stack.pop();
int left = getHigh(inNode.left);
int right = getHigh(inNode.right);
if(Math.abs(left - right) > 1 ) return false;
root = inNode.right;
}
}
return true;
}
public int getHigh(TreeNode node) {
int res = 0;
if(node == null) return res;
Queue<TreeNode> que = new LinkedList<>();
que.offer(node);
while(!que.isEmpty()) {
int size = que.size();
res++;
while(size--> 0) {
TreeNode tem = que.poll();
if(tem.left != null) que.offer(tem.left);
if(tem.right != null) que.offer(tem.right);
}
}
return res;
}
}
二叉树的锯齿遍历
给你二叉树的根节点 root ,返回其节点值的 锯齿形层序遍历 。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)
class Solution {
public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
ArrayList<List<Integer>> ans = new ArrayList<>();
ArrayDeque<TreeNode> curNodes = new ArrayDeque<TreeNode>();
if(root==null){
return ans;
}
curNodes.add(root);
int count=0;
while (!curNodes.isEmpty()){
LinkedList<Integer> temp = new LinkedList<>();
int cursize=curNodes.size();
for (int i = 0; i <cursize ; i++) {
TreeNode curnode = curNodes.remove();
if (count%2==0){
temp.add(curnode.val);
}else {
temp.addFirst(curnode.val);
}
if (curnode.left!=null){
curNodes.add(curnode.left);
}
if (curnode.right!=null){
curNodes.add(curnode.right);
}
}
count++;
ans.add(new ArrayList<Integer>(temp));
}
return ans;
}
}
二叉树的最大深度
给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点。
class Solution {
public int maxDepth(TreeNode root) {
if(root==null){
return 0;
}
int left=maxDepth(root.left);
int right=maxDepth(root.right);
return Math.max(left,right)+1;
}
}
二叉树的最小深度
给定一个二叉树,找出其最小深度。
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
class Solution {
public int minDepth(TreeNode root) {
if(root == null) {
return 0;
} else if(root.left == null && root.right == null) {
return 1;
} else if(root.left == null) {
return minDepth(root.right) + 1;
} else if(root.right == null) {
return minDepth(root.left) + 1;
}
return Math.min(minDepth(root.left) + 1, minDepth(root.right) + 1);
}
}
根节点到叶子结点路径总和
给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。如果存在,返回 true ;否则,返回 false 。
class Solution {
public boolean hasPathSum(TreeNode root, int sum) {
if (root == null) {
return false;
}
if (root.left == null && root.right == null) {
return sum == root.val;
}
return hasPathSum(root.left, sum - root.val) || hasPathSum(root.right, sum - root.val);
}
}
根节点到叶子结点路径总和2
给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。
class Solution {
private List<List<Integer>> anslist;
private List<Integer> curlist;
private List<List<Integer>> ans;
public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
anslist=new ArrayList<>();
ans=new ArrayList<>();
curlist=new ArrayList<Integer>();
dfs(root,curlist,targetSum);
for (int i = 0; i <anslist.size() ; i++) {
List<Integer> integers = anslist.get(i);
int sum=0;
for (int j = 0; j <integers.size() ; j++) {
sum=sum+integers.get(j);
}
if (sum==targetSum){
ans.add(integers);
}
}
return ans;
}
private void dfs(TreeNode root, List<Integer> curlist, int targetSum) {
if (root==null){
return;
}
if (root.right==null&&root.left==null){
curlist.add(root.val);
anslist.add(new ArrayList<>(curlist));
curlist.remove(curlist.size()-1);
return;
}
curlist.add(root.val);
dfs(root.left,curlist,targetSum);
dfs(root.right,curlist,targetSum);
curlist.remove(curlist.size()-1);
}
}
求根节点到叶节点数字之和
给你一个二叉树的根节点 root ,树中每个节点都存放有一个 0 到 9 之间的数字。 每条从根节点到叶节点的路径都代表一个数字:
例如,从根节点到叶节点的路径 1 -> 2 -> 3 表示数字 123 。
从前序与中序遍历序列构造二叉树
给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0re2KIBH-1657510180988)(D:\学习资料\img\1657205228527.png)]
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
if(preorder.length==0 || inorder.length==0) {
return null;
}
TreeNode root = new TreeNode(preorder[0]);
for(int i=0;i<preorder.length;++i) {
if(preorder[0]==inorder[i]) {
int[] pre_left = Arrays.copyOfRange(preorder,1,i+1);
int[] pre_right = Arrays.copyOfRange(preorder,i+1,preorder.length);
int[] in_left = Arrays.copyOfRange(inorder,0,i);
int[] in_right = Arrays.copyOfRange(inorder,i+1,inorder.length);
root.left = buildTree(pre_left,in_left);
root.right = buildTree(pre_right,in_right);
break;
}
}
return root;
}
}
从后序与中序遍历序列构造二叉树
class Solution {
public TreeNode buildTree(int[] inorder, int[] postorder) {
return buildTree(inorder, 0, inorder.length,
postorder, 0, postorder.length);
}
private TreeNode buildTree(int[] inorder, int inLeft, int inRight,
int[] postorder, int postLeft, int postRight){
if(inRight - inLeft < 1) return null;
if (inRight - inLeft == 1) {
return new TreeNode(inorder[inLeft]);
}
TreeNode root = new TreeNode(postorder[postRight - 1]);
int rootIndex = 0;
for(int i = inLeft; i < inRight; i++){
if(inorder[i] == root.val){
rootIndex = i;
}
}
int LENGTH = rootIndex - inLeft;
root.left = buildTree(inorder, inLeft, rootIndex,
postorder, postLeft, postLeft + LENGTH);
root.right = buildTree(inorder, rootIndex + 1, inRight,
postorder,postLeft + LENGTH, postRight - 1);
return root;
}
}
二叉树中序遍历
class Solution {
private List<Integer> ans;
public List<Integer> inorderTraversal(TreeNode root) {
if (root==null){
return new ArrayList<Integer>();
}
ans=new ArrayList<Integer>();
dfs(root);
return ans;
}
public void dfs(TreeNode root) {
if (root==null){
return;
}
dfs(root.left);
ans.add(root.val);
dfs(root.right);
}
}
不同的二叉搜索树
给你一个整数 n ,求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。
class Solution {
public int numTrees(int n) {
int[] dp = new int[n+1];
dp[0]=1;
dp[1]=1;
for (int i = 2; i <n+1 ; i++) {
for (int j = 1; j < i+1; j++) {
dp[i]=dp[i]+dp[j-1]*dp[i-j];
}
}
return dp[n];
}
}
不同的二叉搜索树
给你一个整数 n ,请你生成并返回所有由 n 个节点组成且节点值从 1 到 n 互不相同的不同 二叉搜索树 。可以按 任意顺序 返回答案。
class Solution {
public List<TreeNode> generateTrees(int n) {
if (n == 0) {
return new LinkedList<TreeNode>();
}
return generateTrees(1, n);
}
public List<TreeNode> generateTrees(int start, int end) {
List<TreeNode> allTrees = new LinkedList<TreeNode>();
if (start > end) {
allTrees.add(null);
return allTrees;
}
for (int i = start; i <= end; i++) {
List<TreeNode> leftTrees = generateTrees(start, i - 1);
List<TreeNode> rightTrees = generateTrees(i + 1, end);
for (TreeNode left : leftTrees) {
for (TreeNode right : rightTrees) {
TreeNode currTree = new TreeNode(i);
currTree.left = left;
currTree.right = right;
allTrees.add(currTree);
}
}
}
return allTrees;
}
}
验证二叉搜索树
给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。
class Solution {
private ArrayList<Integer> res;
public boolean isValidBST(TreeNode root) {
res=new ArrayList<>();
midorder(root);
for (int i = 0; i <res.size()-1 ; i++) {
if (res.get(i)>=res.get(i+1)){
return false;
}
}
return true;
}
public void midorder(TreeNode root) {
if (root.left!=null){
midorder(root.left);
}
res.add(root.val);
if (root.right!=null){
midorder(root.right);
}
}
}
回复二叉搜索树
给你二叉搜索树的根节点 root ,该树中的 恰好 两个节点的值被错误地交换。请在不改变其结构的情况下,恢复这棵树 。
class Solution {
private TreeNode x = null;
private TreeNode y = null;
private TreeNode pre = null;
public void recoverTree(TreeNode root) {
dfs(root);
if(x!=null && y!=null) {
int tmp = x.val;
x.val = y.val;
y.val = tmp;
}
}
private void dfs(TreeNode node) {
if(node==null) {
return;
}
dfs(node.left);
if(pre==null) {
pre = node;
}
else {
if(pre.val>node.val) {
y = node;
if(x==null) {
x = pre;
}
}
pre = node;
}
dfs(node.right);
}
}
相同的树
给你两棵二叉树的根节点 p 和 q ,编写一个函数来检验这两棵树是否相同。
如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。
class Solution {
public boolean isSameTree(TreeNode p, TreeNode q) {
return dfs1(p,q);
}
public boolean dfs1(TreeNode p,TreeNode q){
if(p==null&&q==null){
return true;
}
if (p==null||q==null){
return false;
}
if (p.val!=q.val){
return false;
}
return dfs1(p.left,q.left)&&dfs1(p.right,q.right);
}
}
对称二叉树
给你一个二叉树的根节点 root , 检查它是否轴对称。
class Solution {
public boolean isSymmetric(TreeNode root) {
if(root==null) {
return true;
}
return dfs(root.left,root.right);
}
boolean dfs(TreeNode left, TreeNode right) {
if(left==null && right==null) {
return true;
}
if(left==null || right==null) {
return false;
}
if(left.val!=right.val) {
return false;
}
return dfs(left.left,right.right) && dfs(left.right,right.left);
}
}
数组
最长连续序列
给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。
请你设计并实现时间复杂度为 O(n) 的算法解决此问题。
class Solution {
public int longestConsecutive(int[] nums) {
int res=0;
Set<Integer> numsset = new HashSet<>();
for (int i = 0; i <nums.length ; i++) {
numsset.add(nums[i]);
}
for (int x:numsset){
if (!numsset.contains(x-1)){
int y=x;
while (numsset.contains(y+1)){
y++;
}
res=Math.max(res,y-x+1);
}
}
return res;
}
}
搜索旋转排序数组 II
已知存在一个按非降序排列的整数数组 nums ,数组中的值不必互不相同。
在传递给函数之前,nums 在预先未知的某个下标 k(0 <= k < nums.length)上进行了 旋转 ,使数组变为 [nums[k], nums[k+1], …, nums[n-1], nums[0], nums[1], …, nums[k-1]](下标 从 0 开始 计数)。例如, [0,1,2,4,4,4,5,6,6,7] 在下标 5 处经旋转后可能变为 [4,5,6,6,7,0,1,2,4,4] 。
public boolean search(int[] nums, int target) {
if (nums == null || nums.length == 0) {
return false;
}
int start = 0;
int end = nums.length - 1;
int mid;
while (start <= end) {
mid = start + (end - start) / 2;
if (nums[mid] == target) {
return true;
}
if (nums[start] == nums[mid]) {
start++;
continue;
}
if (nums[start] < nums[mid]) {
if (nums[mid] > target && nums[start] <= target) {
end = mid - 1;
} else {
start = mid + 1;
}
} else {
if (nums[mid] < target && nums[end] >= target) {
start = mid + 1;
} else {
end = mid - 1;
}
}
}
return false;
}
删除有序数组的重复项
给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使得出现次数超过两次的元素只出现两次 ,返回删除后数组的新长度。
不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
class Solution {
public int removeDuplicates(int[] nums) {
if (nums.length<3){
return nums.length;
}
int head=2;
int end=2;
while (end<nums.length){
if (nums[end]!=nums[head-2]){
nums[head]=nums[end];
head++;
}
end++;
}
return head;
}
}
颜色分类
给定一个包含红色、白色和蓝色、共 n 个元素的数组 nums ,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。
必须在不使用库的sort函数的情况下解决这个问题。
class Solution {
public static void sortColors(int[] nums) {
int count1=0;
int count2=0;
int count3=0;
for (int i = 0; i <nums.length ; i++) {
if (nums[i]==0){
count1=count1+1;
}
if (nums[i]==1){
count2=count2+1;
}
if (nums[i]==2){
count3=count3+1;
}
}
for (int i = 0; i <count1 ; i++) {
nums[i]=0;
}
for (int i = count1; i <count1+count2 ; i++) {
nums[i]=1;
}
for (int i = count1+count2; i <count1+count2+count3 ; i++) {
nums[i]=2;
}
}
}
搜索二维矩阵
编写一个高效的算法来判断 m x n 矩阵中,是否存在一个目标值。该矩阵具有如下特性:
每行中的整数从左到右按升序排列。 每行的第一个整数大于前一行的最后一个整数。
class Solution {
public boolean searchMatrix(int[][] matrix, int target)
int indexrow=0;
int lie=matrix[0].length;
for (int i = 0; i <matrix.length ; i++) {
if (target>=matrix[i][0]&&target<=matrix[i][lie-1]){
indexrow=i;
break;
}
}
int left=0;
int righ=lie-1;
while (righ>=left){
int midleval=matrix[indexrow][(left+righ)/2];
if (midleval==target){
return true;
}
if (target<midleval){
righ=(left+righ)/2-1;
}
if (target>midleval){
left=(left+righ)/2+1;
}
}
return false;
}
}
矩阵置零
给定一个 *m* x *n* 的矩阵,如果一个元素为 0 ,则将其所在行和列的所有元素都设为 0 。请使用 原地 算法**。**
class Solution {
public void setZeroes(int[][] matrix) {
ArrayList<int[]> adress = new ArrayList<>();
for (int i = 0; i <matrix.length ; i++) {
for (int j = 0; j <matrix[0].length ; j++) {
if (matrix[i][j]==0){
int[] curindex = new int[2];
curindex[0]=i;
curindex[1]=j;
adress.add(curindex);
}
}
}
for (int i = 0; i <adress.size() ; i++) {
int[] index = adress.get(i);
for (int j = 0; j <matrix[0].length ; j++) {
matrix[index[0]][j]=0;
}
for (int j = 0; j <matrix.length ; j++) {
matrix[j][index[1]]=0;
}
}
}
}
插入区间
给你一个 无重叠的 *,*按照区间起始端点排序的区间列表。
在列表中插入一个新的区间,你需要确保列表中的区间仍然有序且不重叠(如果有必要的话,可以合并区间)。
intervals = [[1,3],[6,9]], newInterval = [2,5]
输出:[[1,5],[6,9]]
class Solution {
public int[][] insert(int[][]intervals,int[] newInternal){
int[][] ansmartrix = new int[intervals.length + 1][2];
for (int i = 0; i <intervals.length ; i++) {
for (int j = 0; j <intervals[0].length ; j++) {
ansmartrix[i][j]=intervals[i][j];
}
}
ansmartrix[intervals.length][0]=newInternal[0];
ansmartrix[intervals.length][1]=newInternal[1];
for (int i = 0; i <ansmartrix.length ; i++) {
for (int j = 0; j <ansmartrix.length-i-1 ; j++) {
if (ansmartrix[j][0]>ansmartrix[j+1][0]){
int[] temp=ansmartrix[j];
ansmartrix[j]=ansmartrix[j+1];
ansmartrix[j+1]=temp;
}
}
}
List<List<Integer>> ans = new ArrayList<>();
int[] visit=new int[ansmartrix.length];
for (int i = 0; i <ansmartrix.length ; i++) {
if (visit[i]==1){
continue;
}
int[] temp=ansmartrix[i];
visit[i]=1;
for (int j = i+1; j <ansmartrix.length ; j++) {
if (temp[1]>=ansmartrix[j][0]){
visit[j]=1;
temp[1]=Math.max(temp[1],ansmartrix[j][1]) ;
}
}
List<Integer> tempans = new ArrayList<Integer>();
tempans.add(temp[0]);
tempans.add(temp[1]);
ans.add(tempans);
}
int[][] ints = new int[ans.size()][2];
for (int i = 0; i <ans.size() ; i++) {
List<Integer> integers = ans.get(i);
ints[i][0]=integers.get(0);
ints[i][1]=integers.get(1);
}
return ints;
}
}
合并区间
以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。
class Solution {
public int[][] merge(int[][] martrix){
for (int i = 0; i <martrix.length ; i++) {
for (int j = 0; j <martrix.length-i-1 ; j++) {
if (martrix[j][0]>martrix[j+1][0]){
int[] temp=martrix[j];
martrix[j]=martrix[j+1];
martrix[j+1]=temp;
}
}
}
List<List<Integer>> ans = new ArrayList<>();
int[] visit=new int[martrix.length];
for (int i = 0; i <martrix.length ; i++) {
if (visit[i]==1){
continue;
}
int[] temp=martrix[i];
visit[i]=1;
for (int j = i+1; j <martrix.length ; j++) {
if (temp[1]>=martrix[j][0]){
visit[j]=1;
temp[1]=Math.max(temp[1],martrix[j][1]) ;
}
}
List<Integer> tempans = new ArrayList<Integer>();
tempans.add(temp[0]);
tempans.add(temp[1]);
ans.add(tempans);
}
int[][] ints = new int[ans.size()][2];
for (int i = 0; i <ans.size() ; i++) {
List<Integer> integers = ans.get(i);
ints[i][0]=integers.get(0);
ints[i][1]=integers.get(1);
}
return ints;
}
}
螺旋矩阵
给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素
class Solution {
public static List<Integer> spiralOrder(int[][] matrix){
List<Integer> list = new ArrayList<Integer>();
if(matrix == null || matrix.length == 0)
return list;
int m = matrix.length;
int n = matrix[0].length;
int i = 0;
int count = (Math.min(m, n)+1)/2;
while(i < count) {
for (int j = i; j < n-i; j++) {
list.add(matrix[i][j]);
}
for (int j = i+1; j < m-i; j++) {
list.add(matrix[j][(n-1)-i]);
}
for (int j = (n-1)-(i+1); j >= i && (m-1-i != i); j--) {
list.add(matrix[(m-1)-i][j]);
}
for (int j = (m-1)-(i+1); j >= i+1 && (n-1-i) != i; j--) {
list.add(matrix[j][i]);
}
i++;
}
return list;
}
}
旋转图像
给定一个 n × n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。
class Solution {
public void rotate(int[][] matrix) {
int Length = matrix.length;
for (int i = 0; i <Length/2 ; i++) {
int EndRow=Length-1-i;
for (int j = 0; j <Length; j++) {
int temp=matrix[i][j];
matrix[i][j]=matrix[EndRow][j];
matrix[EndRow][j]=temp;
}
}
for (int i = 0; i <Length ; i++) {
for (int j = 0; j <i ; j++) {
int temp=matrix[i][j];
matrix[i][j]=matrix[j][i];
matrix[j][i]=temp;
}
}
}
}
删除数组重复项
给你一个 升序排列 的数组 nums ,请你** 原地** 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。
class Solution {
public int removeDuplicates(int[] nums) {
int head=0;
int end=1;
while (end<nums.length){
if (nums[head]==nums[end]){
end++;
}else {
nums[head+1]=nums[end];
head++;
end++;
}
}
return head+1;
}
}
在排序数组中查找元素的最后和第一个位置
你一个按照非递减顺序排列的整数数组 nums ,和一个目标值 target 。请你找出给定目标值在数组中的开始位置和结束位置
class Solution {
private List<Integer> ans;
public int[] searchRange(int[] nums,int target){
ans = new ArrayList<Integer>();
binarysearch(nums,0,nums.length-1,target);
System.out.println(ans);
int[] ansarray=new int[2];
int max = ans.get(0);
int min=ans.get(0);
for (int i = 0; i <ans.size() ; i++) {
if (ans.get(i)>max){
max=ans.get(i);
}
if (ans.get(i)<min){
min=ans.get(i);
}
}
ansarray[0]=min;
ansarray[1]=max;
return ansarray;
}
public void binarysearch(int[] nums,int left,int right,int target){
if (left>right){
ans.add(-1);
ans.add(-1);
return;
}
int midle=(left+right)/2;
int midleval=nums[midle];
if (target<midleval){
binarysearch(nums,left,midle-1,target);
}else if (target>midleval){
binarysearch(nums,midle+1,right,target);
}else {
ans.add(midle);
int temp=midle-1;
while (true){
if (temp<0||nums[temp]!=target){
break;
}else {
ans.add(temp);
temp=temp-1;
}
}
temp=midle+1;
while (true){
if (temp>nums.length-1||nums[temp]!=target){
break;
}else {
ans.add(temp);
temp=temp+1;
}
}
}
}
}
外观数列
给定一个正整数 n ,输出外观数列的第 n 项。
「外观数列」是一个整数序列,从数字 1 开始,序列中的每一项都是对前一项的描述。
你可以将其视作是由递归公式定义的数字字符串序列:
countAndSay(1) = “1” countAndSay(n) 是对 countAndSay(n-1) 的描述,然后转换成另一个数字字符串。
class Solution {
public static String countAndSay(int n){
if(n==1){
return "1";
}
String string=countAndSay(n-1);
char[] charn=string.toCharArray();
List<Character> counts= new ArrayList<>();
List<Character> chars=new ArrayList<>();
int left=0;
int right=0;
int count=0;
while (right<charn.length){
if (charn[left]!=charn[right]){
counts.add(Integer.toString(count).charAt(0));
chars.add(charn[left]);
left=right;
count=0;
}else {
count=count+1;
right=right+1;
}
}
counts.add(Integer.toString(count).charAt(0));
chars.add(charn[charn.length-1]);
StringBuilder ans= new StringBuilder();
for (int i = 0; i <counts.size() ; i++) {
ans.append(counts.get(i));
ans.append(chars.get(i));
}
return ans.toString();
}
}
路径系列
三角形最小路径和
给定一个三角形 triangle ,找出自顶向下的最小路径和。
每一步只能移动到下一行中相邻的结点上。相邻的结点 在这里指的是 下标 与 上一层结点下标 相同或者等于 上一层结点下标 + 1 的两个结点。也就是说,如果正位于当前行的下标 i ,那么下一步可以移动到下一行的下标 i 或 i + 1 。
class Solution {
public int minimumTotal(List<List<Integer>> triangle) {
int[][] grid = new int[triangle.size()][triangle.size()];
for (int i = 0; i <triangle.size() ; i++) {
List<Integer> integers = triangle.get(i);
for (int j = 0; j <integers.size() ; j++) {
grid[i][j]=integers.get(j);
}
}
return dp(grid);
}
private int dp(int[][] grid){
int[][] dp = new int[grid.length][grid[0].length];
dp[0][0]=grid[0][0];
for (int i = 1; i <grid.length ; i++) {
for (int j = 0; j <=i ; j++) {
if (j==0){
dp[i][j]=grid[i][j]+dp[i-1][j];
continue;
}
if (i==j){
dp[i][j]=grid[i][j]+dp[i-1][j-1];
continue;
}
dp[i][j]=0;
}
}
for (int i = 2; i <grid.length ; i++) {
for (int j = 1; j <i ; j++) {
dp[i][j]=grid[i][j]+Math.min(dp[i-1][j],dp[i-1][j-1]);
}
}
int sum=Integer.MAX_VALUE;
for (int i = 0; i <grid.length ; i++) {
if (dp[grid.length-1][i]<sum){
sum=dp[grid.length-1][i];
}
}
return sum;
}
}
单词搜索
给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。
单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
class Solution {
private int[][] direction={{-1,0},{0,1},{1,0},{0,-1}};
private boolean[][] visit;
private char[] chars;
public static void main(String[] args) {
}
public boolean exist(char[][] board, String word) {
visit=new boolean[board.length][board[0].length];
int row=board.length;
int lie =board[0].length;
chars = word.toCharArray();
for (int i = 0; i <row ; i++) {
for (int j = 0; j <lie ; j++) {
if (dfs(i,j,0,chars,board)){
return true;
}
}
}
return false;
}
public boolean dfs(int x,int y,int index,char[] str,char[][] board){
if (index==str.length-1&&str[index]==board[x][y]&&!visit[x][y]){
return true;
}
if (str[index]==board[x][y]&&!visit[x][y]){
visit[x][y]=true;
for (int i = 0; i <direction.length ; i++) {
int newx=x+ direction[i][0];
int newy=y+ direction[i][1];
if (newx>=0&&newx<=board.length-1&&newy>=0&&newy<=board[0].length-1&&!visit[newx][newy]) {
if (dfs(newx, newy, index + 1, str, board)) {
return true;
}
}
continue;
}
}
visit[x][y]=false;
return false;
}
}
不同路径
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。
问总共有多少条不同的路径?
class Solution {
public int uniquePaths(int m, int n) {
return dfs(new HashMap<Pair,Integer>(), 0, 0, m, n);
}
private int dfs(Map<Pair,Integer> cache, int i, int j, int m, int n) {
Pair p = new Pair(i,j);
if(cache.containsKey(p)) {
return cache.get(p);
}
if(i == m - 1 || j == n - 1) {
return 1;
}
cache.put(p, dfs(cache, i + 1, j, m, n) + dfs(cache, i, j + 1, m, n) );
return cache.get(p);
}
}
class Solution {
public int uniquePaths(int m, int n) {
int[][] dp = new int[m][n];
for (int k = 0; k <m ; k++) {
dp[k][0]=1;
}
for (int k = 0; k <n ; k++) {
dp[0][k]=1;
}
for (int k = 1; k <m ; k++) {
for (int l = 1; l <n ; l++) {
dp[k][l]=dp[k-1][l]+dp[k][l-1];
}
}
return dp[m-1][n-1];
}
}
不同路径2
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish”)。
现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?
网格中的障碍物和空位置分别用 1 和 0 来表示。
class Solution {
public int uniquePathsWithObstacles(int[][] obstacleGrid){
int row = obstacleGrid.length;
int lie=obstacleGrid[0].length;
if (row==1){
for (int i = 0; i <obstacleGrid[0].length ; i++) {
if (obstacleGrid[0][i]==1){
return 0;
}
}
}
if (lie==1){
for (int i = 0; i <obstacleGrid.length ; i++) {
if (obstacleGrid[i][0]==1){
return 0;
}
}
}
int[][] dp = new int[row][lie];
for (int i = 0; i <obstacleGrid.length ; i++) {
if (obstacleGrid[i][0]==1){
for (int j = i; j <obstacleGrid.length ; j++) {
dp[j][0]=0;
}
break;
}
dp[i][0]=1;
}
for (int i = 0; i <obstacleGrid[0].length ; i++) {
if (obstacleGrid[0][i]==1){
for (int j = i; j <obstacleGrid[0].length ; j++) {
dp[0][i]=0;
}
break;
}
dp[0][i]=1;
}
for (int i = 1; i <obstacleGrid.length ; i++) {
for (int j = 1; j <obstacleGrid[0].length ; j++) {
if (obstacleGrid[i][j]==1){
dp[i][j]=0;
continue;
}
dp[i][j]=dp[i-1][j]+dp[i][j-1];
}
}
return dp[dp.length-1][dp[0].length-1];
}
}
最小路径和
给定一个包含非负整数的 *m* x *n* 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
class Solution {
public int minPathSum(int[][] grid) {
int row = grid.length;
int lie = grid[0].length;
if (row==1){
int sum=0;
for (int i=0;i<grid[0].length;i++){
sum=sum+grid[0][i];
}
return sum;
}
if (lie==1){
int sum=0;
for (int i=0;i<grid.length;i++){
sum=sum+grid[i][0];
}
return sum;
}
int[][] dp=new int[row][lie];
int sum=0;
for (int i=0;i<grid[0].length;i++){
sum=sum+grid[0][i];
dp[0][i]=sum;
}
sum=0;
for (int i=0;i<grid.length;i++){
sum=sum+grid[i][0];
dp[i][0]=sum;
}
for (int i = 1; i <grid.length ; i++) {
for (int j = 1; j <grid[0].length ; j++) {
dp[i][j]=grid[i][j]+Math.min(dp[i-1][j],dp[i][j-1]);
}
}
return dp[row-1][lie-1];
}
}
排列组合
数组元素组合3
给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。
输入:nums = [1,2,2]
输出:[[],[1],[1,2],[1,2,2],[2],[2,2]]
class Solution {
private List<List<Integer>> ans;
private List<Integer> curans;
private boolean[] check;
public List<List<Integer>> subsetsWithDup(int[] nums) {
check=new boolean[nums.length];
curans=new ArrayList<Integer>();
ans=new ArrayList<List<Integer>>();
for (int i = 0; i <nums.length ; i++) {
for (int j = 0; j <nums.length-i-1 ; j++) {
if (nums[j]<nums[j+1]){
int temp=nums[j];
nums[j]=nums[j+1];
nums[j+1]=temp;
}
}
}
for (int i = 0; i <=nums.length ; i++) {
dfs(0,nums,i,curans,check);
}
return ans;
}
public void dfs(int curindex,int[] nums,int n,List<Integer> curans,boolean[] check){
if (curans.size()==n){
List<Integer> integers = new ArrayList<>(curans);
ans.add(integers);
return;
}
for (int i = curindex; i <nums.length ; i++) {
if (check[i]==true){
continue;
}
if (i!=0&&nums[i-1]==nums[i]&&check[i-1]==false){
continue;
}
curans.add(nums[i]);
check[i]=true;
dfs(i+1,nums,n,curans,check);
curans.remove(curans.size()-1);
check[i]=false;
}
}
}
数组元素组合2
给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。
nums = [1,2,3]
输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
class Solution {
private List<List<Integer>> ans;
private List<Integer> curans;
public List<List<Integer>> subsets(int[] nums) {
ans=new ArrayList<List<Integer>>();
curans=new ArrayList<Integer>();
for (int i = 0; i <nums.length+1 ; i++) {
dfs(nums,0,0,i,curans);
}
return ans;
}
public void dfs(int[] nums,int index,int cruk,int k,List<Integer> curans){
if (cruk==k){
List<Integer> curans1=new ArrayList<Integer>(curans);
ans.add(curans1);
return;
}
for (int i =index; i <nums.length ; i++) {
curans.add(nums[i]);
dfs(nums,i+1,cruk+1,k,curans);
curans.remove(curans.size()-1);
}
}
}
数组元素组合
给定两个整数 n 和 k ,返回范围 [1, n] 中所有可能的 k 个数的组合。
class Solution {
private List<List<Integer>> ans;
private List<Integer> curans;
public List<List<Integer>> combine(int n, int k) {
ans=new ArrayList<List<Integer>>();
curans=new ArrayList<Integer>();
int[] nums=new int[n];
for (int i = 0; i <n ; i++) {
nums[i]=i+1;
}
dfs(nums,0,0,k,curans);
return ans;
}
public void dfs(int[] nums,int index,int cruk,int k,List<Integer> curans){
if (cruk==k){
List<Integer> curans1=new ArrayList<Integer>(curans);
ans.add(curans1);
return;
}
for (int i =index; i <nums.length ; i++) {
curans.add(nums[i]);
dfs(nums,i+1,cruk+1,k,curans);
curans.remove(curans.size()-1);
}
}
}
全排列
给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。
nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
class Solution {
private List<List<Integer>> ans;
private List<Integer> curans;
private int length;
public List<List<Integer>> permute(int[] nums){
ans=new ArrayList<List<Integer>>();
curans=new ArrayList<Integer>();
length=nums.length;
dfs(nums, 0);
System.out.println(ans);
return ans;
}
private void dfs(int[] nums, int index) {
if (curans.size()==length){
ArrayList<Integer> integers = new ArrayList<>(curans);
ans.add(integers);
return;
}
for (int i = index; i <length ; i++) {
boolean falg=true;
int num = nums[i];
for (int j = 0; j <curans.size() ; j++) {
if (num==curans.get(j)){
falg=false;
}
}
if (falg==false){
continue;
}
curans.add(nums[i]);
dfs(nums,0);
curans.remove(curans.size()-1);
}
}
}
全排列2
定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。
nums = [1,1,2]
输出:
[[1,1,2],
[1,2,1],
[2,1,1]]
class Solution {
private List<List<Integer>> ans;
private List<Integer> curans;
private int length;
private int[] visit;
public List<List<Integer>> permuteUnique(int[] nums){
ans=new ArrayList<List<Integer>>();
curans=new ArrayList<Integer>();
length=nums.length;
visit=new int[length];
Arrays.sort(nums);
for (int i = 0; i <visit.length ; i++) {
visit[i]=0;
}
dfs(nums,0);
return ans;
}
public void dfs(int[] nums,int index){
if (curans.size()==length){
ans.add(new ArrayList<Integer>(curans));
return;
}
for (int i = index; i <length ; i++) {
if (visit[i]==1){
continue;
}
if (i>index&&nums[i]==nums[i-1]&&visit[i-1]==0){
continue;
}
visit[i]=1;
curans.add(nums[i]);
dfs(nums,index);
visit[i]=0;
curans.remove(curans.size()-1);
}
}
}
总数组合
给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。
candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。
candidates = [2,3,6,7], target = 7
输出:[[2,2,3],[7]]
class Solution {
private List<List<Integer>> res;
private int length;
private List<Integer> curans;
public List<List<Integer>> combinationSum(int[] candidates, int target) {
res=new ArrayList<List<Integer>>();
curans=new ArrayList<Integer>();
length=candidates.length;
if (length==0){
return res;
}
dfs(candidates,0,target);
return res;
}
private void dfs(int[] candidates, int index,int target) {
if (target<0){
return;
}
if (target==0){
ArrayList<Integer> integers = new ArrayList<>(curans);
res.add(integers);
return;
}
for (int i = index; i <length ; i++) {
curans.add(candidates[i]);
dfs(candidates,i,target-candidates[i]);
curans.remove(curans.size()-1);
}
}
}
总数组合2
给定一个候选人编号的集合?candidates?和一个目标数?target?,找出?candidates?中所有可以使数字和为?target?的组合。
candidates?中的每个数字在每个组合中只能使用?一次?。
private int length;
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
if (candidates.length==0){
return ans;
}
Arrays.sort(candidates);
ans =new ArrayList<List<Integer>>();
curans=new ArrayList<Integer>();
length=candidates.length;
dfs(candidates,0,target);
return ans;
}
private void dfs(int[] candidates,int index, int target) {
if (target==0){
ArrayList<Integer> integers = new ArrayList<>(curans);
ans.add(integers);
return;
}
if (target<0){
return;
}
for (int i =index; i <length ; i++) {
if (i>index&&candidates[i]==candidates[i-1]){
continue;
}
curans.add(candidates[i]);
dfs(candidates,i+1,target-candidates[i]);
curans.remove(curans.size()-1);
}
}
}
跳跃游戏
给你一个非负整数数组 nums ,你最初位于数组的第一个位置。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
你的目标是使用最少的跳跃次数到达数组的最后一个位置。
假设你总是可以到达数组的最后一个位置
nums = [2,3,1,1,4]
输出: 2
class Solution {
public int jump(int[] nums) {
if (nums.length==0||nums.length==1){
return 0;
}
int end = nums[0] + 1;
int start = 0;
int maxpro = 0;
int count = 1;
while (end < nums.length) {
for (int i = 0; i < end; i++) {
if (maxpro < i + nums[i]) {
maxpro = i + nums[i];
}
}
count++;
start = end;
end = maxpro + 1;
}
return count;
}
}
跳跃游戏2
给定一个非负整数数组 nums ,你最初位于数组的 第一个下标 。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
判断你是否能够到达最后一个下标。
class Solution {
public boolean canJump(int[] nums) {
if(nums.length==1) return true;
int length=nums.length-1;
int maxindex=0;
int tmp=0;
for (int i = 0; i < nums.length; i++) {
tmp=i+nums[i];
if(tmp==maxindex && nums[i]==0) {
return false;
}
maxindex=Math.max(tmp, maxindex);
if(maxindex>=length) {
return true;
}
}
return false;
}
}
电话号码的字母组合
给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
class Solution {
private String letterMap[] = {
" ",
"",
"abc",
"def",
"ghi",
"jkl",
"mno",
"pqrs",
"tuv",
"wxyz"
};
private ArrayList<String> res;
public List<String> letterCombinations(String digits) {
res = new ArrayList<String>();
if(digits.equals(""))
return res;
findCombination(digits, 0, "");
return res;
}
private void findCombination(String digits, int index, String s){
if(index == digits.length()){
res.add(s);
return;
}
Character c = digits.charAt(index);
String letters = letterMap[c - '0'];
for(int i = 0 ; i < letters.length() ; i ++){
findCombination(digits, index+1, s + letters.charAt(i));
}
return;
}
}
下一个排列
整数数组的 下一个排列 是指其整数的下一个字典序更大的排列。更正式地,如果数组的所有排列根据其字典顺序从小到大排列在一个容器中,那么数组的 下一个排列 就是在这个有序容器中排在它后面的那个排列。如果不存在下一个更大的排列,那么这个数组必须重排为字典序最小的排列(即,其元素按升序排列)。
例如,arr = [1,2,3] 的下一个排列是 [1,3,2] 。 类似地,arr = [2,3,1] 的下一个排列是 [3,1,2] 。
class Solution {
public void nextPermutation(int[] nums) {
if (nums.length<2){
return;
}
int left=nums.length-2;
int right=nums.length-1;
while (left>=0){
if (nums[left]<nums[right]){
break;
}
left--;
right--;
}
if (left<0){
Arrays.sort(nums);
return;
}else {
if (right==nums.length-1){
int temp=nums[left];
nums[left]=nums[right];
nums[right]=temp;
return;
}else {
int k=nums.length-1;
while (k>right){
if (nums[k]>nums[left]){
break;
}
k--;
}
int temp=nums[left];
nums[left]=nums[k];
nums[k]=temp;
for (int i = right; i <nums.length ; i++) {
for (int j = right; j <nums.length-1; j++) {
if (nums[j]>nums[j+1]){
temp=nums[j];
nums[j]=nums[j+1];
nums[j+1]=temp;
}
}
}
}
}
}
}
格雷编码
class Solution {
List<Integer> res = new ArrayList<>();
public List<Integer> grayCode(int n) {
dfs(n,new StringBuffer(),new int[]{0,1});
return res;
}
public void dfs(int n, StringBuffer sb, int[] nums){
if(sb.length() == n){
res.add(Integer.valueOf(sb.toString(),2));
return;
}
sb.append(nums[0]);
dfs(n,sb,new int[]{0,1});
sb.deleteCharAt(sb.length()-1);
sb.append(nums[1]);
dfs(n,sb,new int[]{1,0});
sb.deleteCharAt(sb.length()-1);
}
}
死锁
Object A = new Object();
Object B = new Object();
Thread t1 = new Thread(() -> {
synchronized (A) {
log.debug("lock A");
sleep(1);
synchronized (B) {
log.debug("lock B");
log.debug("操作...");
}
}
}, "t1");
Thread t2 = new Thread(() -> {
synchronized (B) {
log.debug("lock B");
sleep(0.5);
synchronized (A) {
log.debug("lock A");
log.debug("操作...");
}
}
}, "t2");
t1.start();
t2.start();
活锁
public class TestLiveLock {
static volatile int count = 10;
static final Object lock = new Object();
public static void main(String[] args) {
new Thread(() -> {
while (count > 0) {
sleep(0.2);
count--;
log.debug("count: {}", count);
}
}, "t1").start();
new Thread(() -> {
while (count < 20) {
sleep(0.2);
count++;
log.debug("count: {}", count);
}
}, "t2").start();
}
}
下(与电话按键相同)。注意 1 不对应任何字母。
class Solution {
private String letterMap[] = {
" ",
"",
"abc",
"def",
"ghi",
"jkl",
"mno",
"pqrs",
"tuv",
"wxyz"
};
private ArrayList<String> res;
public List<String> letterCombinations(String digits) {
res = new ArrayList<String>();
if(digits.equals(""))
return res;
findCombination(digits, 0, "");
return res;
}
private void findCombination(String digits, int index, String s){
if(index == digits.length()){
res.add(s);
return;
}
Character c = digits.charAt(index);
String letters = letterMap[c - '0'];
for(int i = 0 ; i < letters.length() ; i ++){
findCombination(digits, index+1, s + letters.charAt(i));
}
return;
}
}
下一个排列
整数数组的 下一个排列 是指其整数的下一个字典序更大的排列。更正式地,如果数组的所有排列根据其字典顺序从小到大排列在一个容器中,那么数组的 下一个排列 就是在这个有序容器中排在它后面的那个排列。如果不存在下一个更大的排列,那么这个数组必须重排为字典序最小的排列(即,其元素按升序排列)。
例如,arr = [1,2,3] 的下一个排列是 [1,3,2] 。 类似地,arr = [2,3,1] 的下一个排列是 [3,1,2] 。
class Solution {
public void nextPermutation(int[] nums) {
if (nums.length<2){
return;
}
int left=nums.length-2;
int right=nums.length-1;
while (left>=0){
if (nums[left]<nums[right]){
break;
}
left--;
right--;
}
if (left<0){
Arrays.sort(nums);
return;
}else {
if (right==nums.length-1){
int temp=nums[left];
nums[left]=nums[right];
nums[right]=temp;
return;
}else {
int k=nums.length-1;
while (k>right){
if (nums[k]>nums[left]){
break;
}
k--;
}
int temp=nums[left];
nums[left]=nums[k];
nums[k]=temp;
for (int i = right; i <nums.length ; i++) {
for (int j = right; j <nums.length-1; j++) {
if (nums[j]>nums[j+1]){
temp=nums[j];
nums[j]=nums[j+1];
nums[j+1]=temp;
}
}
}
}
}
}
}
格雷编码
class Solution {
List<Integer> res = new ArrayList<>();
public List<Integer> grayCode(int n) {
dfs(n,new StringBuffer(),new int[]{0,1});
return res;
}
public void dfs(int n, StringBuffer sb, int[] nums){
if(sb.length() == n){
res.add(Integer.valueOf(sb.toString(),2));
return;
}
sb.append(nums[0]);
dfs(n,sb,new int[]{0,1});
sb.deleteCharAt(sb.length()-1);
sb.append(nums[1]);
dfs(n,sb,new int[]{1,0});
sb.deleteCharAt(sb.length()-1);
}
}
死锁
Object A = new Object();
Object B = new Object();
Thread t1 = new Thread(() -> {
synchronized (A) {
log.debug("lock A");
sleep(1);
synchronized (B) {
log.debug("lock B");
log.debug("操作...");
}
}
}, "t1");
Thread t2 = new Thread(() -> {
synchronized (B) {
log.debug("lock B");
sleep(0.5);
synchronized (A) {
log.debug("lock A");
log.debug("操作...");
}
}
}, "t2");
t1.start();
t2.start();
活锁
public class TestLiveLock {
static volatile int count = 10;
static final Object lock = new Object();
public static void main(String[] args) {
new Thread(() -> {
while (count > 0) {
sleep(0.2);
count--;
log.debug("count: {}", count);
}
}, "t1").start();
new Thread(() -> {
while (count < 20) {
sleep(0.2);
count++;
log.debug("count: {}", count);
}
}, "t2").start();
}
}
|