算法高级学习1

一、大楼轮廓(有序表) 给定一个 N×3 的矩阵 matrix,对于每一个长度为 3 的小数组 arr,都表示一个大楼的三个数 据。
arr[0]表示大楼的左边界,arr[1]表示大楼的右边界,arr[2]表示大楼的高度(一定大于 0)。
每座大楼的地基都在 X 轴上,大楼之间可能会有重叠,请返回整体的轮廓线数组。
【举例】
matrix = { {2,5,6}, {1,7,4}, {4,6,7}, {3,6,5}, {10,13,2}, {9,11,3}, {12,14,4}, {10,12,5} }
返回:
【算法高级学习1】{{1,2,4}, {2,4,6}, {4,6,7}, {6,7,4}, {9,10,3}, {10,12,5},{12,14,4}}

/** * @Author: 郜宇博 */ public class BuildingBorder { public static void main(String[] args) { int[][] matrix = new int[][]{ {2,7,3}, {3,5,5}, {4,6,4} }; List> buildingBorder = getBuildingBorder(matrix); System.out.println(buildingBorder); } /** * 用于记录高度变化 */ public static class Node{ public int index; public boolean isAdd; public int height; public Node(int index, boolean isAdd, int height) { this.index = index; this.isAdd = isAdd; this.height = height; } } public static List> getBuildingBorder(int[][] matrix){ Node[] nodes = getHeightUpDown(matrix); //构造两个有序表 //坐标-高度表 TreeMap indexHeightMap = new TreeMap<>(); //高度-次数表 TreeMap heightTimesMap = new TreeMap<>(); fillMap(indexHeightMap,heightTimesMap,nodes); //返回结果 return getBorder(indexHeightMap); } public static List> getBorder(TreeMap indexHeightMap){ List> res = new ArrayList<>(); int start = indexHeightMap.firstKey(); int preHeight = indexHeightMap.get(start); for (Map.Entry entry: indexHeightMap.entrySet()){ //如果高度发生变化 if (entry.getValue() != preHeight){ //添加(start,curKey,preHeight) List border= null; if (preHeight != 0){ border = new ArrayList<>(Arrays.asList(start,entry.getKey(),preHeight)); res.add(border); } //新的list,起始点,高度都变了 start = entry.getKey(); preHeight = entry.getValue(); } } return res; } /** * 填充map表 */ public static void fillMap(TreeMap indexHeightMap,TreeMap heightTimesMap,Node[] nodes){ for (Node node: nodes){ //是否为添加 if (node.isAdd){ //1.处理heightTimesMap //添加过,次数+1 if (heightTimesMap.containsKey(node.height)){ heightTimesMap.put(node.height,heightTimesMap.get(node.height)+1); }else { //没添加guo heightTimesMap.put(node.height,1); } }else { //下降 if (heightTimesMap.get(node.height)==1){ //删除后为0,则移除 heightTimesMap.remove(node.height); }else { heightTimesMap.put(node.height,heightTimesMap.get(node.height)-1); } } //2.处理indexHeightMap //没有高度了,到结尾了 //获取最大高度 Integer maxHeight =heightTimesMap.isEmpty()?0:heightTimesMap.lastKey(); indexHeightMap.put(node.index,maxHeight); } } /** * 获取高度变化的数组,返回排序后的结果 */ public static Node[] getHeightUpDown(int[][] matrix){ Node[] resultNode = new Node[matrix.length * 2]; for (int i= 0; i < matrix.length; i++){ for (int j = 0; j < matrix[0].length ; j++){ resultNode[i * 2] = new Node(matrix[i][0],true,matrix[i][2]); resultNode[i * 2+1] = new Node(matrix[i][1],false,matrix[i][2]); } } //按照index大小排序,相同的话根据add在前,排序,防止出现线状楼 Arrays.sort(resultNode,(x,y)->{ if (x.index != y.index){ return x.index - y.index; } if (x.isAdd != y.isAdd){ return x.isAdd?-1:1; } return 0; }); return resultNode; } }

二、最长子数组等于k(构造单调性、滑动窗口) 给定一个数组 arr,该数组无序,但每个值均为正数,再给定一个正数 k。
求 arr 的 所有子 数组中所有元素相加和为 k 的最长子数组长度。
例如,arr=[1,2,1,1,1],k=3。
累加和为 3 的最长子数组为[1,1,1],所以结果返回 3。
要求:时间复杂度O(N),额外空间复杂度O(1)
/** * @Author: 郜宇博 * 给定一个数组 arr,该数组无序,但每个值均为正数,再给定一个正数 k。 * 求 arr 的 所有子 数组中所有元素相加和为 k 的最长子数组长度。 */ public class LongestChildArraySumK { public static void main(String[] args) { int len = 30; int k = 15; int[] arr = generatePositiveArray(len); System.out.println(getLongestCount(arr, k)); }/** * 构造单调性,因为数组都是正数,保持一个区间, * 当区间内sum < k时,继续扩充区间 * 当区间sum = k 时,以i为起点,此区间最大了,更换区间,r++, l++ * 当sum > k时,如果l,r在同一位置,都向后移动,不在的话,left++,缩小区域 */ public static int getLongestCount(int[] array, int target){ int left = 0; int right = 0; // sum =[left,...,right] int sum = array[0]; int result = Integer.MIN_VALUE; while (right != array.length){ //sum = array[right]; if (sum == target){ result = Math.max(result, right - left + 1); if (right == array.length-1){ return Math.max(result, 0); } sum = sum - array[left++] + array[++right]; } else if (sum < target){ if (right == array.length-1){ return Math.max(result, 0); } sum += array[++right]; }else { if (left == right){ sum = array[++left]; right++; }else { sum -= array[left++]; } } } return Math.max(result, 0); } public static int[] generatePositiveArray(int size) { int[] result = new int[size]; for (int i = 0; i != size; i++) { result[i] = (int) (Math.random() * 10) + 1; } return result; } }

三、拿硬币 给定一个非负数组,每一个值代表该位置上有几个铜板。
a和b玩游戏,a先手,b后手, 轮到某个人的时候,只能在一个位置上拿任意数量的铜板,但是不能不拿。
谁最先把铜板拿完谁赢。假设a和b都极度聪明,请返回获胜者的名字。
/** * @Author: 郜宇博 * 给定一个非负数组,每一个值代表该位置上有几个铜板。 * a和b玩游戏,a先手,b后手, 轮到某个人的时候,只能在一个位置上拿任意数量的铜板,但是不能不拿。 * 谁最先把铜板拿完谁赢。假设a和b都极度聪明,请返回获胜者的名字。 */ public class PickMoneyWin { public static void main(String[] args) { int[] array = new int[]{3,4,1}; System.out.println(getWinner(array)); } /** * 最后桌子上剩下1个硬币时,先手赢,否则后手赢 * 将所有数字求异或和,为0说明先手怎么都赢不了 */ public static String getWinner(int[] array){ int eorResult = 0; for (int num: array){ eorResult ^= num; } return eorResult==0?"后手":"先手"; } }

四、最长子数组小于等于k(舍去部分解) 给定一个无序数组 arr,其中元素可正、可负、可 0,给定一个整数 k。
求 arr 所 有的子数组 中累加和小于或等于 k 的最长子数组长度。
例如:arr=[3,-2,-4,0,6],k=-2,相加和小于或等于-2 的最长子数组为{3,-2,-4,0},所以结果返回4。
/** * @Author: 郜宇博 * 给定一个无序数组 arr,其中元素可正、可负、可0,给定一个整数k。 * 求arr 所有的子数组累加和小于或等于k的最长子数组长度。 */ public class LongestChildArraySumLessK { public static void main(String[] args) { int[] array = new int[]{3,-2,-4,0,6}; System.out.println(getSumLessK(array,-2)); } public static int getSumLessK(int[] array, int target) { //准备两个数组 //1.以i开始,向后最小sum //2.到达最小sum的边界坐标 int[] minSum = new int[array.length]; int[] minBorder = new int[array.length]; minSum[array.length - 1] = array[array.length - 1]; minBorder[array.length - 1] = array.length - 1; for (int i = array.length - 2; i >= 0; i--) { minSum[i] = array[i]; minBorder[i] = i; //如果右边的最小和<0,那么应该向右拓展 if (minSum[i + 1] <= 0) { minSum[i] += minSum[i + 1]; minBorder[i] = minBorder[i + 1]; } } int left = 0; int right = 0; int result = 0; int curSum = 0; for (; array.length - left > result; left++) { //不越界,并且满足条件 while (right < array.length && minSum[right] + curSum <= target) { //更新curSum curSum += minSum[right]; right = minBorder[right] + 1; } //找到了以left为左边界最长满足条件的数组,更新 result = Math.max(result,right - left); //边界整体向右移动(!重点) if (left == right){ right++; }else { curSum -= array[left]; } } return result; } }

    推荐阅读