小和问题
在一个数组中, 每一个数左边比当前数小的数累加起来, 叫做这个数组的小和。 求一个数组的小和。例子:
[1,2,3,4]
1左边比1小的数, 没有;
2左边比2小的数, 1;
3左边比3小的数, 1, 2;
4左边比4小的数, 1,2,3,;
所以小和为1+1+2+1+2+3=10
思路:归并排序的思想,在将两个数组merge的过程中统计右边有多少个数大于左边的这个数,然后乘于个数最后相加即可.
public class work1 {
public static int mergeSort(int[] arr, int left, int right) {
if(left == right)
return 0;
int mid = left + (right - left) / 2;
return mergeSort(arr, left, mid) + mergeSort(arr, mid+1, right)
+ merge(arr, left, mid, right);
}
public static int merge(int[] arr, int left, int mid, int right) {
int[] help = new int[right - left +1];
int i = 0;
int res = 0;
int p1 = left;
int p2 = mid + 1;
while(p1 <= mid && p2 <= right) {
//在合并的时候计算右边有多少个元素大于arr[p1],然后arr[p1]与个数相乘后加起来.
res += arr[p1] < arr[p2]? arr[p1] *(right - p2 + 1) : 0;
help[i++] = arr[p1] < arr[p2]? arr[p1++] : arr[p2++];
}
while(p1 <= mid) {
help[i++] = arr[p1++];
}
while(p2 <= right) {
help[i++] = arr[p2++];
}
for(i = 0; i < help.length; i++)
arr[left + i] = help[i];
return res;
}
public static void main(String[] args)
{
int[] arr = new int[] {1,2,3,4};
System.out.print("原始数组:");
for(int i = 0; i < arr.length; i++)
if(i != arr.length - 1)
System.out.print(arr[i] + " ");
else
System.out.println(arr[i]);
int sum = mergeSort(arr, 0 ,arr.length - 1);
System.out.print("小数和:");
System.out.println(sum);
}
}
运行结果:
荷兰国旗问题:例如,给定数组:[334,6,323,44,88,88,56,90],给定一个值88,那么经过处理原数组可能得一种情况是:[56, 6, 44, 88, 88, 323, 90, 334],需要注意的是,小于88的部分不需要有序,大于88的部分也不需要有序,返回等于4部分的左右两个下标,即[3, 4]
思路:快排的思想,使用两个指针分别维护左边小于num的区间与右边大于num的区间,扫描一遍即可完成左边小于num,右边大于num,但左边和右边不需要有序.
import java.util.Scanner;
public class work2 {
public static int[] partition(int[] arr, int L, int R, int num) {
int less = L - 1;
int more = R + 1;
while(L < more) {
if(arr[L] < num) {
swap(arr, ++less, L++);
}else if(arr[L] > num) {
swap(arr, --more, L);
}else {
L++;
}
}
return new int[]{less + 1, more - 1};
}
public static void swap(int[] arr, int i,int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
public static void main(String[] args) {
int[] arr = new int[]{334,6,323,44,88,88,56,90};
System.out.print("原始数组:");
for(int i = 0; i < arr.length; i++)
if(i != arr.length - 1)
System.out.print(arr[i] + " ");
else
System.out.println(arr[i]);
System.out.print("请输入一个整数:");
Scanner in = new Scanner(System.in);
int num = in.nextInt();
int[] p = partition(arr, 0, arr.length - 1, num);
System.out.println("partition之后");
for(int i = 0; i < arr.length; i++)
if(i != arr.length - 1)
System.out.print(arr[i] + " ");
else
System.out.println(arr[i]);
System.out.println(num + "的左边界为:" + p[0] + ",右边界为:" + p[1]);
}
}
运行结果: