与宣扬

风云中平淡,平淡中成长。

导航

数据结构和局部算法

/** 以下是力扣刷题总结内容 */
/** 双指针
*	快慢指针
*	头尾指针
*/
/** 二分法 —— 按条件快速查找 */
	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;
    }
}

posted on 2021-08-18 13:46  与宣扬  阅读(60)  评论(0)    收藏  举报