/* 给你三个正整数 n、index 和 maxSum 。你需要构造一个同时满足下述所有条件的数组 nums(下标 从 0 开始 计数): nums.length == n nums[i] 是 正整数 ,其中 0 <= i < n abs(nums[i] - nums[i+1]) <= 1 ,其中 0 <= i < n-1 nums 中所有元素之和不超过 maxSum nums[index] 的值被 最大化 返回你所构造的数组中的 nums[index] 。 示例1: 输入:n = 4, index = 2, maxSum = 6 输出:2 解释:数组 [1,1,2,1] 和 [1,2,2,1] 满足所有条件。不存在其他在指定下标处具有更大值的有效数组。 示例2: 输入:n = 6, index = 1, maxSum = 10 输出:3 */ // 用main 方法简单做测试吧 public class 有界数组中指定下标处的最大值1802 { public static void main(String[] args) { int n = 10042; int index = 4321; int maxSum = 999999977; System.out.println(maxValue(n,index,maxSum) == maxValue1(n,index,maxSum)); } /** * 二分 + 贪心 * maxValue二分查找 * valid贪心 * cal 求mid左边或右边的总和 * @param n 数组长度 * @param index 极大值位置 * @param maxSum 所有元素总和 * @return */ //方法一:官方求解方式,已吃透,欢迎讨论 public static int maxValue(int n, int index, int maxSum) { int left = 1, right = maxSum; while (left < right) { int mid = (left + right + 1) / 2; if (valid(n,index,mid,maxSum)) { left = mid; } else { right = mid - 1; } } return left; } public static boolean valid(int n, int index, int mid, int maxSum) { int lefts = index, rights = n - index -1; return mid + cal(mid,lefts) + cal(mid,rights) <= maxSum; } public static long cal (int big,int length) { if (length + 1 < big) { int small = big - length; return (long)(big - 1 + small) * length / 2; } else { int ones = length - (big - 1); return (long)(big - 1) * big / 2 + ones; } } // 方法二:自己没看参考直接写的方法,可惜超时了! public static int maxValue1(int n, int index, int maxSum) { int[] nums = new int[n]; int sal = maxSum - n - 1; nums[index] = sal >= 0 ? 2 : 1; int left = index; int right = n - index -1; int status = 0; // 4 5 5 5 4 3 // 1 1 2 1 1 1 for (int i = 0; i < sal; ) { if (i < sal) { if (status < n && status == 0) { status++; } if (left > 0 && status < n) { left--; status++; } if (right > 0 && status < n) { right--; status++; } sal = sal - status; } if (sal >= 0) { nums[index]++; } } return nums[index]; }
}