[Offer收割]编程练习赛12 题目4 : 寻找最大值
时间限制:10000ms
单点时限:1000ms
内存限制:256MB
描述
给定N个数A1, A2, A3, ... AN,小Ho想从中找到两个数Ai和Aj(i ≠ j)使得乘积Ai × Aj × (Ai AND Aj)最大。其中AND是按位与操作。
小Ho当然知道怎么做。现在他想把这个问题交给你。
输入
第一行一个数T,表示数据组数。(1 <= T <= 10)
对于每一组数据:
第一行一个整数N(1<=N<=100,000)
第二行N个整数A1, A2, A3, ... AN (0 <= Ai <220)
输出
一个数表示答案
- 样例输入
-
2 3 1 2 3 4 1 2 4 5
- 样例输出
-
12 80
思路
(1)优化穷举。先对整数从小到大排序,从后往前求解数对的结果,并更新max。对于a,b两个数,Ai × Aj × (Ai AND Aj)的最大值为 a * b * Math.min(a, b),因此可以利用此性质对O(n^2)的解法进行优化。
(2)贪心。先对整数从小到大排序,Ai × Aj × (Ai AND Aj)的最大值只有可能出现在排序后相邻的两个元素的情况(Why?)
代码
(1)
1 import java.util.Arrays; 2 import java.util.Scanner; 3 4 public class BasicMain { 5 6 public static long max(int[] nums) { 7 final int n = nums.length; 8 long max = 0; 9 for (int i = n - 1; i >= 0; i--) { 10 for (int j = n - 1; j > i; j--) { 11 long tmp = (long) nums[i] * nums[j]; 12 if (tmp * nums[i] <= max) // 优化,后续不可能有超过max的值 13 break; 14 15 max = Math.max(max, tmp * (nums[i] & nums[j])); 16 } 17 } 18 return max; 19 } 20 21 public static void main(String[] args) { 22 Scanner sc = new Scanner(System.in); 23 int cases = sc.nextInt(); 24 for (int c = 0; c < cases; c++) { 25 int n = sc.nextInt(); 26 int[] nums = new int[n]; 27 for (int i = 0; i < n; i++) { 28 nums[i] = sc.nextInt(); 29 } 30 Arrays.sort(nums); 31 System.out.println(max(nums)); 32 } 33 } 34 }
(2)
1 import java.util.Arrays; 2 import java.util.Scanner; 3 4 public class Main { 5 6 public static long max(int[] nums) { 7 final int n = nums.length; 8 long max = 0; 9 for (int i = 0; i < n - 1; i++) { 10 max = Math.max(max, (long) nums[i] * nums[i + 1] * (nums[i] & nums[i + 1])); 11 } 12 return max; 13 } 14 15 public static void main(String[] args) { 16 Scanner sc = new Scanner(System.in); 17 int cases = sc.nextInt(); 18 for (int c = 0; c < cases; c++) { 19 int n = sc.nextInt(); 20 int[] nums = new int[n]; 21 for (int i = 0; i < n; i++) { 22 nums[i] = sc.nextInt(); 23 } 24 Arrays.sort(nums); 25 System.out.println(max(nums)); 26 } 27 } 28 }