1. 给你一个无序数组,找出数组中的一个数,使得在数组中,这个数之前的所有数字之和等于这个数之后所有数字之和。
输入:
输入一行数字,每个数字用逗号隔开。
输出:
存在这个数,则输出这个数。不存在这个数,则输出False。
样例:
输入:
1,3,4,4
输出
4
解题思路:
(1)遍历数组法
看到这题,第一个想法就是从头到尾遍历数组,然后计算左边之和,右边之和,比较它们。
代码:
public static int stuFind(int[] array){
for(int i=1;i<array.length;i++){
int totalLeft=0;
for(int le=0;le<i;le++){
totalLeft+=array[le];
}
int totalRight=0;
for(int ri=i+1;ri<array.length;ri++){
totalRight+=array[ri];
}
if(totalLeft==totalRight){
return i;
}
}
return -1;
}
(2)对遍历数组的优化法
遍历法时间复杂度应该是O()。其实还可以优化一下,反正是顺序后移,计算可以偷懒一下,当你第一次计算左边的值和右边的值以后,第二次移动,左边的值等于原先左边的值+当前位置前一个位置的值,右边的值等于原先右边的值减去当前的位置的数字的值。
代码:
public static int stuFind(int[] array){
int totalLeft=0;
int totalRight=0;
for(int i=1;i<array.length;i++){
if(i==1){
for(int le=0;le<i;le++){
totalLeft+=array[le];
}
for(int ri=i+1;ri<array.length;ri++){
totalRight+=array[ri];
}
}else{
totalLeft+=array[i-1];
totalRight-=array[i];
}
if(totalLeft==totalRight){
return i;
}
}
return -1;
}
(3)二分查找法
既然某个数字的左边的值等于右边,那么可以算出数组的全部数值,然后加入一个二分查找的办法,定位到中间,如果左边的值*2=数组的和-当前位置的值,那么就可以说找到了,如果大于,那就向前移动,小于就向后移动。
思考:为什么要左边的值*2,而不是(数组的和-当前位置的值)/2 ?
我的想法是:(数组的和 - 当前位置的值)/ 2 的值可能为float类型。在Java中会对这个值自动的向下取整,变成int类型。那么在进行(数组的和 - 当前位置的值)/ 2 = 左边值的和 比较的时候,就会出现精度的偏差。
最优代码:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc = new Scanner(System.in);
String str = sc.next();
String[] strArray = str.split(",");
int[] array = new int[strArray.length];
for(int i=0; i<strArray.length; i++) {
array[i] = Integer.parseInt(strArray[i]);
}
int index = splitFindNum(array);
if(index == -1) {
System.out.println("False");
}else {
System.out.println(array[index]);
}
}
public static int splitFindNum(int[] array) {
if (null == array || array.length == 0) {
return -1;
}
int length = array.length;
int low, high, index;
low = 0;
high = length - 1;
index = length / 2;
int sum = 0;
for (int i : array) {
sum += i;
}
do {
int totalLow = 0;
for (int le = 0; le < index; le++) {
totalLow += array[le];
}
int doub2Val=(sum - array[index]);
if (totalLow*2 < doub2Val) {
low=index;
index = index + (length - index) / 2;
} else if (totalLow*2 > doub2Val) {
high=index;
index = low + (index - low) / 2;
} else {
return index;
}
} while (index > low && index < high);
return -1;
}
}
Reference:
2.给你两个无序数组M、N,输出两个数组中和最大的前K个数。在求和时,一个数来自M、另一个数来自N。
输入:输入一行,数组间用横杠(-)隔开,数组内数字用逗号隔开,最后用冒号隔开K。
输出:输出一行,输出前K大的数,每个数字用逗号隔开。
样例:
输入:
2,4,2,7,7-3,2,5,6,1,9:6
输出:
16,16,13,13,13,12
解题思路:
(1)排序法
首先对M、N进行快速排序,然后求出数组中任意两个数字的和,再对所有的和进行排序,选出前K大的数字。这样写首先时间复杂度太高,不知道能不能AC,其次这个算法肯定是不行的,感觉是拿不到offer的。
代码:
import java.util.Scanner;
public class Main2 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc = new Scanner(System.in);
String str = sc.next();
String[] twoStr = str.split(":");
int k = Integer.parseInt(twoStr[1]);
String[] twoArray = twoStr[0].split("-");
String[] m2Str = twoArray[0].split(",");
int[] M = new int[m2Str.length];
String[] n2Str = twoArray[1].split(",");
int[] N = new int[n2Str.length];
for(int i=0; i<m2Str.length;i++) {
M[i] = Integer.parseInt(m2Str[i]);
}
for(int j= 0; j<n2Str.length;j++) {
N[j] = Integer.parseInt(n2Str[j]);
}
quickSort(M,0,M.length-1);
quickSort(N, 0, N.length-1);
int[] sum = new int[M.length * N.length];
int l=0;
for(int i=0; i< M.length; i++) {
for(int j=0; j<N.length; j++) {
sum[l] = M[i] + N[j];
l++;
}
}
quickSort(sum, 0, sum.length-1);
int temp = sum.length;
String output = "";
while(temp > sum.length - k) {
temp--;
output += sum[temp] + ",";
}
System.out.println(output.substring(0,output.length()-1));
}
public static void quickSort(int[] arr, int start, int end) {
if (start < end) {
int key = arr[start];
int right = start;
int left = end;
while (right < left) {
while (right < left && arr[left] > key) {
left --;
}
if (right < left) {
arr[right] = arr[left];
}
while (right < left && arr[right] <= key) {
right ++;
}
if (right < left) {
arr[left] = arr[right];
}
}
arr[right] = key;
quickSort(arr, start, right-1);
quickSort(arr, left+1, end);
}
}
}