1300. 转变数组后最接近目标值的数组和 双重二分法

1300. 转变数组后最接近目标值的数组和

难度:中等 2020/6/14每日一题打卡√
头昏昏
题目描述
1300. 转变数组后最接近目标值的数组和 双重二分法_第1张图片
解题思路
题目标签里给了二分法,那就用二分法来做吧~
每次查找用了两次二分法,第一个查找在数组中小于目标值的右边界,第二个查找总和大于目标值的值,左边界。最后还要比较左边和右边哪个最接近

/*
		 * 1300. 转变数组后最接近目标值的数组和
		 * 2020/6/14每日一题打卡√
		 */
		public static int findBestValue(int[] arr, int target) {
			Arrays.sort(arr);
			int value = 0,n = arr.length,re = 0,min = Integer.MAX_VALUE,avg = 0;
			int[] sum = new int[n+1];
			for (int i = 0; i < n; i++) {
				sum[i+1] = sum[i]+arr[i];
			}
			if(sum[n] <= target) {//如果整个数组的和都小于target,直接返回最大值
				return arr[n-1];
			}
			int left = 0,right = arr[n-1];  //二分查找的范围[0~数组最大值]
			while(left < right) {
				int mid = left + (right - left)/2;
				//二分查找确定小于mid的下标
				int index = findHelper(0, n-1, arr,mid);
				int getsum = sum[index+1] + (n-index-1)*mid;
				if(getsum < target) { //如果严格小,那么肯定不是解
					left = mid + 1;
				}else {
					right = mid;
				}	
			}
			int index = findHelper(0, n-1, arr,left);
			int sum1 = sum[index+1] + (n-index-1)*left;
			index = findHelper(0, n-1, arr,left-1);
			int sum2 = sum[index+1] + (n-index-1)*(left-1);
			//sum1大于目标,sum2小于目标
			if (sum2 - target <= target - sum1) {
		          return left - 1;
		     }
		     return left;

	    }
		
		//找到小于目标值的最左边元素(右边界)
		public static int findHelper(int left,int right,int[] arr,int max) {
			while(left < right) {
				//先排除不是解的情况
				int mid = left + (right - left + 1)/2;
				if(arr[mid] > max) {
					right = mid - 1;
				}else {
					left = mid;
				}
			}
			// 需要做后处理
	        if (arr[left] <= max) {
	            return left;
	        }
	        // 说明 arr 中所有值都大于 target
	        return -1;
		}

1300. 转变数组后最接近目标值的数组和 双重二分法_第2张图片

折腾了好久,还有一种不用二分法的办法,跟做数学题差不多,先对数组排序,每次动态更新平均值,如果某一个数大于平均值,就把这个数和后面的数都变成平均值四舍五入的结果。

public int findBestValue(int[] arr, int target) {
			int n = arr.length;
			Arrays.sort(arr);
			int sum = 0,avg = 0;
			for (int i = 0; i < n; i++) {  //找到所有比平均值小的数字值
				avg = (target - sum)/(n-i);
				if(arr[i] <= avg)
					sum += arr[i];
				else {
					double tmp = (double)(target - sum) / (n - i);
	                if(tmp - avg > 0.5) 
	                	return avg + 1;
	                else 
	                	return avg;
				}
			}
			return arr[n-1];
		}

1300. 转变数组后最接近目标值的数组和 双重二分法_第3张图片

你可能感兴趣的:(力扣刷题笔记)