/** 以下是力扣刷题总结内容 */
/** 双指针
* 快慢指针
* 头尾指针
*/
/** 二分法 —— 按条件快速查找 */
int left = 0;
int right = increase.length - 1;
while (left < right) {
int mid = left + (right - left) / 2;
if (increase[mid] < target) { //不符合条件
left = mid + 1;
} else {
right = mid;
}
}
return left; // 符合条件元素下标
/** 分治法 —— 将复杂问题分为简单问题求解,将结果合并 */
/** 动态规划 —— 最少,最短 */
/** DFS —— 递归 */
// 广度优先遍历
Queue<Integer> queue = new LinkedList<Integer>();
queue.offer(0);
while (!queue.isEmpty()) {
int size = queue.size();
for (int i = 0; i < size; i++) { // 获取当前队列中元素
int index = queue.poll();
List<Integer> list = edges.get(index);
for (int nextIndex : list) { // 添加下一层遍历得到的元素
queue.offer(nextIndex);
}
}
}
// 深度优先遍历
public void dfs(int index) {
List<Integer> list = edges.get(index); //获取当前元素对应的下层元素
for (int nextIndex : list) { // 对每个下层元素递归获取内容
dfs(nextIndex);
}
}
/** 摩尔投票法
* 候选人(cand_num)初始化为nums[0],票数count初始化为1。
* 当遇到与cand_num相同的数,则票数count = count + 1,否则票数count = count - 1。
* 当票数count为0时,更换候选人,并将票数count重置为1。
* 遍历完数组后,cand_num即为最终答案。*/
public int majorityElement(int[] nums) {
int cand_num = nums[0], count = 1;
for (int i = 1; i < nums.length; ++i) {
if (cand_num == nums[i])
++count;
else if (--count == 0) {
cand_num = nums[i];
count = 1;
}
}
return cand_num;
}
/** 树 */
/** 中序遍历 */
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> list = new ArrayList<Integer>();
Stack<TreeNode> stack = new Stack<>();
TreeNode cur = root;
while(cur != null || !stack.isEmpty()){
if(cur != null){
stack.push(cur);
cur = cur.left;
}else{
cur = stack.pop();
list.add(cur.val);
cur = cur.right;
}
}
return list;
}
/** 前缀树
* 根节点不包含字符,除根节点外每一个节点都只包含一个字符。
* 从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串。
* 每个节点的所有子节点包含的字符都不相同。
* */
class Trie {
private Trie[] children;
private boolean isEnd;
public Trie() {
children = new Trie[26];
isEnd = false;
}
public void insert(String word) {
Trie node = this;
for (int i = 0; i < word.length(); i++) {
char ch = word.charAt(i);
int index = ch - 'a';
if (node.children[index] == null) {
node.children[index] = new Trie();
}
node = node.children[index];
}
node.isEnd = true;
}
public Trie[] getChildren() {
return children;
}
public boolean isEnd() {
return isEnd;
}
}
/**以下是程序员小灰学习资料自我总结内容*/
class ListNode{ //链表
int val;
ListNode next;
ListNode(int x){ this.val = x;}
}
class TreeNode{
int val;
TreeNode left;
TreeNode right;
}
class Grammer{
//冒泡排序 n*n
public void bubbleSort(int[] arr, int n){
for(int i = 0; i < n; i++){
for(int j = 0; j < n-i-1; j++){
if(arr[j] > arr[j+1]){
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
}
//插入排序 n*n
public void insertSort(int[] arr){
for(int i = 1; i < arr.length; i++){
//要插入元素及下标
int insertVal = arr[i];
int index = i-1;
while(index >= 0 && insertVal < arr[index]){
arr[index+1] = arr[index]; //原来数据后移
index--;
}
arr[index+1] = insertVal;
}
}
//希尔排序 分段插入排序 略优于n*n,不足nlogn
public void shellSort(int[] arr){
int dk = arr.length/2;
while(dk >= 1){
shellInsert(arr, dk);
dk = dk/2;
}
}
private void shellInsert(int[] arr, int dk){
//类似插入,将1改为dk
for(int i = dk; i < arr.length; i++){
if(arr[i] < a[i-dk]){
int x = a[i];
a[i] = a[i-dk];
for(int j = i-dk; j >= 0 && x < a[j]; j = j -dk){
a[j+dk] = a[j];
}
a[j+dk] = x;
}
}
}
//快速排序 递归 nlogn
public void quickSort(int[] arr, int low, int high){
int start = low, end = high, key = arr[low];
while(end > start){
while(end > start && arr[end] >= key) //从后往前找比key小的值
end--;
if(arr[end] <= key){
int temp = arr[end];
arr[end] = arr[start];
arr[start] = temp;
}
while(end > start && arr[start] <= key) //从前往后找比key大的值
start++;
if(arr[start] >= key){
int temp = arr[start];
arr[start] = a[end];
arr[end] = temp;
}
}
//左右两侧数据递归排序
if(start > low) quickSort(arr, low, start-1);
if(end < high) quickSort(arr, end+1, high);
}
//归并排序 nlogn jdk底层排序
public mergerSort(int[] arr, int left, int right){ //初始值 0,length-1
if(left >= right) return;
int center(left+right)/2;
//左右两侧递归排序
sort(arr,left, center);
sort(arrm center+1, right);
//合并
int[] tmpArr = new int[arr.length];
int mid = center+1, third = left, tmp = left;//右数组第一元素索引,临时数组索引,左数组第一元素索引
while(left <= center && mid <= right){
if(arr[left] <= arr[mid]){
tmpArr[third++] = arr[left++];
}else{
tmpArr[third++] = arr[mid++];
}
}
//剩余合并
while(mid <= right){
tmpArr[third++] = arr[mid++];
}
while(left <= center){
tmpArr[third++] = arr[left++];
}
//原 left-right 范围的内容被复制回原数组
while(tmp <= right){
arr[tmp] = tmpArr[tmp++];
}
}
//非递归前序遍历
public void preOrderTraveralWithStack(TreeNode root){
Stack<TreeNode> stack = new Stack();
TreeNode treeNode = root;
while(treeNode != null || !stack.isEmpty()){
//访问左侧子节点,并入栈
while(treeNode != null){
System.out.println(treeNode.val);
stack.push(treeNode);
treeNode = treeNode.left;
}
//如果没有左侧子节点,弹出栈顶节点,访问右侧子节点
if(!stack.isEmpty()){
treeNode = stack.pop();
treeNode = treeNode.right;
}
}
}
//层序遍历
public void levelOrderTraversal(TreeNode root){
Queue<TreeNode> queue = new LinkedList<TreeNode>();
queue.offer(root);
while(!queue.isEmpty()){
TreeNode node = queue.poll();
System.out.println(node.val);
if(node.left != null){
queue.offer(node.left);
}
if(node.right != null){
queue.offer(node.right);
}
}
}
//上浮
public void upAdjust(int[] array){
int childIndex = array.length-1;
int parentIndex = (childIndex-1)/2;
int temp = array[childIndex];
while(childIndex > 0 && temp < array[parentIndex]){
array[childIndex] = array[parentIndex];
childIndex = parentIndex;
parentIndex = (parentIndex-1)/2;
}
array[childIndex] = temp;
}
//下沉,要下沉的父节点,堆的有效大小
public void downAdjust(int[] array, int parentIndex, int length){
int temp = array[parentIndex];
int childIndex = 2*parentIndex+1;
while(childIndex < length){
//如果有右孩子,且右孩子小于左孩子,则定位到右孩子
if(childIndex+1 < length && array[childIndex+1] <array[childIndex]){
childIndex++;
}
//如果父节点小于任何子节点 跳出循环
if(temp <= array[childIndex]){
break;
}
array[parentIndex] = array[childIndex];
parentIndex = childIndex;
childIndex = 2*childIndex+1;
}
}
//构建二叉堆
public void buildHeap(int[] array){
//从最后一个非叶子节点开始下沉
for(inti = (array.length-2)/2; i >= 0; i--){
downAdjust(array, i, array.length);
}
}
//堆排序 nlogn 255
public void downAdjusts(int[] array, int parentIndex, int length){
int temp = array[parentIndex];
int childIndex = 2* parentIndex+1;
while(childIndex < length){
if(childIndex+1 < length && array[childIndex+1] < array[childIndex]){
childIndex++;
}
if(temp >= array[childIndex])
break;
array[parentIndex] = array[childIndex];
parentIndex = childIndex;
childIndex = 2*childIndex+1;
}
array[parentIndex] = temp;
}
public void heapSort(int[] array){
for(int i = (array.length-2)/2; i >= 0; i--){
downAdjusts(array, i, array.length);
}
//循环删除堆顶,调整产生新的堆顶
for(int i = array.length-1; i > 0; i--){
//首尾元素交换
int temp = array[i];
array[i] = array[0];
array[0] = temp;
downAdjusts(array, 0, i); //下沉调整最大堆
}
}
//计数排序 数据在小范围内,统计个数排序 n
public int[] countSort(int[] array){
int max = array[0], min = array[0]; //获取最大值,最小值
for(int i = 1; i < array.length; i++){
if(array[i] > max){
max = array[i];
}
if(array[i] < min){
min = array[i];
}
}
int[] countArray = new int[max-min+1]; //计数
for(int i = 0; i < array.length; i++){
countArray[array[i]-min]++;
}
for(int i = 1; i < countArray.length; i++){ //统计变形
countArray[i] += countArray[i-1];
}
int[] sortedArray = new int[array.length];//排序
for(int i = array.length-1; i >= 0; i--){
sortedArray[countArray[array[i]-min]-1] = array[i];
countArray[array[i]-min]--;
}
return sortedArray;
}
//桶排序 浮点数的计数排序 n
public double[] bucketSort(double[] array){
double max = array[0], min = array[0];
for(int i = 1; i < array.length; i++){
if(array[i] > max){
max = array[i];
}if(array[i] < min){
min = array[i];
}
}
ArrayList<LinkedList<Double>> bucketList = new ArrayList<LinkedList<Double>>(array.length);
for(int i = 0; i < array.length; i++){
bucketList.add(new LinkedList<Double>());
}
for(int i = 0; i < array.length; i++){
int num = (int)((array[i] - min) * (array.length-1)/(max-min));
bucketList.get(num).add(array[i]);
}
for(int i = 0; i < bucketList.size(); i++){
Collections.sort(bucketList.get(i));
}
double[] sortedArray = new double[array.length];
int index = 0;
for(LinkedList<Double> list: bucketList){
for(double element : list){
sortedArray[index++] = element;
}
}
return sortedArray;
}
//二分查找
public int biSearch(int[] array, int a){
int left = 0, right = array.length-1;
int mid = 0;
while(left <= right){
mid = (left+right)/2;
if(array[mid] == a){ //找到元素
return mid+1;
}else if(array[mid] < a){ //向右查找
left = mid+1;
}else{ //向左查找
right = mid-1;
}
}
return -1; //未找到元素
}
//判断链表有环
public boolean isCycle(ListNode head){
ListNode fast = head, slow = head;
while(fast != null && fast.next != null){
slow = slow.next;
fast = fast.next.next;
if(fast == slow){
//首次相遇后,计算步数,当再次相遇时获得环长
//首次相遇后,slow指向头结点,再次相遇节点为入环节点
return true;
}
}
return false;
}
//最小栈实现
class MinStack{
private Stack<Integer> stack = new Stack();
private Stack<Integer> minStack = new Stack();
public void push(int element){
stack.push(element);
if(minStack.isEmpty() || element <= minStack.peek()){
minStack.push(element);
}
}
public Integer pop(){
if(stack.peek().equals(minStack.peek())){
minStack.pop();
}
return stack.pop();
}
public int getMin() throw Exception{
if(stack.isEmpty()){
throw new Exception("stack is empty");
}
return minStack.peek();
}
}
//最大公约数 辗转相除法,欧几里得
public int getGreatestCommonDivisor(int a, int b){
if(a == b) return a;
if((a&1) == 0 && (b&1) == 0)
return getGreatestCommonDivisor(a>>1, b>>1);
else if((a&1) == 0 && (b&1) != 0)
return getGreatestCommonDivisor(a>>1, b);
else if((a&1) != 0 && (b&1) == 0)
return getGreatestCommonDivisor(a, b>>1);
else{
int big = a>b ? a:b;
int small = a<b ? a:b;
return getGreatestCommonDivisor(big-small, small);
}
}
//判定数为二次幂
public boolean isPowOf2(int num){
return (num & num-1) == 0;
}
//无序数组排序后的最大相邻差 桶排序
private class Bucket{
Integer max;
Integer min;
}
public int gerMaxSort(int[] array){
int max = array[0];
int min = array[0];
for(int i = 1; i < array.length; i++){
if(array[i] > max){
max =array[i];
if(array[i] < min)
min = array[i];
}
}
if(max-min == 0)
return 0;
Bucket[] buckets = new Bucket[array.length];
for(int i = 0; i < array.length; i++){
buckets[i] = new Bucket();
int index = ((array[i]-min)*(array.length-1)/(max=min));
if(buckets[index].min == null || buckets[index].min > array[i])
buckets[index],min = array[i];
if(buckets[index].max == null || buckets[index].max < array[i])
buckets[index].max = array[i];
}
int leftMax= buckets[0].max, maxDistance = 0;
for(int i = 1; i < buckets.length; i++){
if(buckets[i].min == null)
continue;
if(buckets[i].min-leftMax > maxDistance)
maxDistance = buckets[i].min-leftMax;
leftMax = buckets[i].max;
}
return maxDistance;
}
//队列实现栈
private Stack<Integer> stackA = new Stack<Integer>();
private Stack<Integer> stackB = new Stack<Integer>();
public void enQueue(int element){
stackA.push(element);
}
public Integer deQueue(){
if(stackB.isEmpty()){
while(!stackA.isEmpty()){
stackB.push(stackA.pop());
}
}
return stackB.pop();
}
//获得全排列下一个数
public int[] findNearestNumber(int[] number){
//从后向前查看逆序区域,获得区域前一位,数字置换边界
int index = 0;
for(int i = number.length-1; i >= 0; i--){
if(number[i] > number[i-1]){
index = i;
break;
}
}
if(index == 0)
return null;
//把逆序区域前一位和逆序中刚大于它的数字交换
int[] numberCopy = Arrays.copyOf(numberm number.length);
int head = numberCopy[index-1];
for(int i = numberCopy.length-1; i > 0; i--){
if(head < numberCopy[i]){
numberCopy[index-1] = numb[i];
numberCopy[i] = head;
break;
}
}
//把原来的逆序区域转为顺序
for(int i = index, j = numberCopy.length-1; i < j; i++, j--){
int temp = numberCopy[i];
numberCopy[i] = number[j];
numberCopy[j] = temp;
}
return numberCopy;
}
//删去k个数字后的最小值
public String removeDigit(String num, int k){
int newLength = num.length()-k;
//创建一个栈,接受所有数据
char[] stack = new char[num.length()];
int top = 0;
for(int i = 0; i< num.length(); i++){
char c = num.charAt(i);
//当栈顶数字大于遍历到的当前数字时,栈顶数字出栈
while(top > 0 && stack[top-1] > c && k > 0){
top --;
k--;
}
stack[top++] = c;
}
//找到栈中第一个非零数字的位置,构建新的整数字符串
int offset = 0;
while(offset < newLength && stack[offset] == '0'){
offset++;
}
return offset == newLength ? "0" : new String(stack, offset, newLength-offset);
}
//大数相加
public String bigBumberSum(String a, String b){
int maxLength = a.length()>b.length()> a.length(): b.length();
int[] array = new int[maxLength+1];
for(int i = 0; i < array.length; i++){
int temp = array[i];
if(a.length()-1-i >= 0)
temp += a.charAt(a.length()-1-i)-'0';
if(b.length()-1-i >= 0)
temp += b.charAt(b.length()-1-i)-'0';
if(temp >= 10){
temp = temp-10;
array[i+1] = 1;
}
array[i] = temp;
}
StringBuilder ans = new StringBuilder();
boolean findFirst = false;
for(int i = array.length-1; i >= 0; i--){
if(!findFirst){
if(array[i] == 0){
continue;
}
findFirst = true;
}
ans.append(array[i]);
}
return ans.toString();
}
//求解金矿 背包问题
//工人数量,金矿开采需人工数,金矿储量
public int getBestGoldMining(int w, int[] p, int[] g){
int[][] result = new int[g.length+1][w+1];
for(int i = 1; i <= g.length; i++){
for(int j = 1; j <= w; j++){
if(j < p[i-1])
result[i][j] = result[i-1][j];
else
result[i][j] = Math.max(result[i-1][j], result[i-1][j-p[i-1]]+g[i-1]);
}
}
return result[g.length][w];
}
//全排列中缺失的数据 分治
public int[] findLostNum(int[] array){
int[] result = new int[2];
int xor = 0;
for(int i = 0; i < array.length; i++){
xor ^= array[i];
}
if(xor == 0)
return null;
int separator = 1;
while(0 == (xor & separator)){
separator <<= 1;
}
for(int i = 0; i < array.length; i++){
if(0 == (array[i] & separator))
result[0] ^= array[i];
else
result[1] ^= array[i];
}
return result;
}
//LRU缓存 最近最少使用
class Node{
Node(String key, String value){
this.key = key;this.value = value;
}
public Node pre;
public Node next;
public String key;
public String value;
}
private Node head, end;
private int limit;//缓存存储上限
private HashMap<String, Node> hashMap;
public LRUCache(int limit){
this.limit = limit;
hashMap = new HashMap();
}
public get(String key){
Node node = hashMap.get(key);
if(node == null)
return null;
refreshNode(node);
return node.value;
}
public void put(String key, String value){
Node node = hashMap.get(key);
if(node == null){
if(hashMap.size() >= limit){
String oldkey =removeNode(head);
hashMap.remove(oldkey);
}
node = new Node(key, value);
addNode(node);
hashMap.put(key, node);
}else{
node.value = value;
refreshNode(node);
}
}
public void remove(String key){
Node node = hashMap.get(key);
removeNode(node);
hashMap.remove(key);
}
private void refreshNode(Node node){ //更新使用状态
if(node == end) return;
removeNode(node);
addNode(node);
}
private String removeNode(Node node){
if(head == node && end == node){ //只有一个节点
head = null; end = null;
}else if(node == end){
end = end.pre;
end.next = null;
}else if(node == head){
head = head.next;
head.pre = null;
}else{
node.pre,next = node.next;
node.next.pre = node.pre;
}
return node.key;
}
private void addNode(Node node){ //添加数据到链表尾部
if(end != null){
end.next = node;
node.pre = en;
node.next = null;
}
end = node;
if(head == null){
head = node;
}
}
//A星寻路算法
public final int[][] MAZE{
{0,0,0,0,0,0,0},
{0,0,0,1,0,0,0},
{0,0,0,1,0,0,0},
{0,0,0,1,0,0,0},
{0,0,0,0,0,0,0},
};
class Grid{
public int x, y, f, g, h;
public Grid parent;
public Grid(int x, int y){
this.x = x; this.y = y;
}
public void initGrid(Grid parent, Grid end){
this.parent = parent;
if(parent != null){
this.g = parent.g+1;
}else{
this.g = 1;
}
this.h = Math.abs(this.x-end.x)+Math.abs(this.y-end.y);
this.f = this.g+this.h;
}
}
public Grid aStartSearch(Grid start, Grid end){
ArrayList<Grid> openList = new ArrayList(); //可前进位置
ArrayList<Grid> closeList = new ArrayList(); //已走过位置
openList.add(start);
while(openList.size() > 0){
Grid currentGrid = findMinGrid(openList);
openList.remove(currentGrid);
closeList.add(currentGrid);
List<Grid> neighbors = findNeighbors(currentGrid, openList,closeList);
for(Grid grid : neighbors){
if(!openList.contains(grid)){
grid.initGrid(currentGrid, end);
openList.add(grid);
}
if(grid.x == end.x && grid.y = end.y){ //如果终点在openlist 直接返回终点
return grid;
}
}
}
return null;
}
private Grid findMinGrid(ArrayList<Grid> openList){
Grid tempGrid = openList.get(0);
for(Grid grid: openList){
if(grid.f < tempGrid.f)
tempGrid = grid;
}
return tempGrid;
}
private ArrayList<Grid> findNeighbors(Grid grid, List<Grid> openList, List<Grid> closeList){
ArrayList<Grid> gridlist = new ArrayList();
if(isValidGrid(grid.x, grid.y-1, openList, closeList))
gridlist.add(new Grid(grid.x, grid.y-1));
if(isValidGrid(grid.x, grid.y+1, openList, closeList))
gridlist.add(new Grid(grid.x, grid.y+1));
if(isValidGrid(grid.x-1, grid.y, openList, closeList))
gridlist.add(new Grid(grid.x-1, grid.y));
if(isValidGrid(grid.x+1, grid.y, openList, closeList))
gridlist.add(new Grid(grid.x+1, grid.y));
return gridlist;
}
private boolean isValidGrid(int x,int y, List<Grid> openList, List<Grid> closeList){
if(x < 0 || x >= MAZE.length || y < 0 || y >= MAZE[0].length)
return false;
if(MAZE[x][y] == 1) //有障碍
return false;
if(containsGrid(openList, x, y) || containsGrid(closeList, x, y))
return false;
return true;
}
private boolean containsGrid(List<Grid> grids, int x, int y){
for(Grid n: grids){
if(n.x == x && n.y == y){
return true;
}
}
return false;
}
//红包算法
//二倍均值法 红包=0.01——剩余金额/剩余人数*2-0.01
public List<integer> divideRedPackage(Integer totalAmount, Integer totalPeopleNum){
List<Integer> amountList = new ArrayList<Integer>();
Integer restAmount = totalAmount;
Integer restPeoPleNum = totalPeopleNum;
Random random = new Random();
for(int i = 0; i < totalPeopleNum-1; i++){
int amount = random.nextInt(restAmount/restPeoPleNum*2-1)+1;
restAmount -= amount;
restPeoPleNum--;
amountList.add(amount);
}
amountList.add(restAmount);
return amountList;
}
}