1 题目1 所有同学往右侧看到的同学之和
青海大学的体育课经常排在上午3、4节,一节课下来大家都筋疲力尽、饥肠辘辘。将近下课,体育老师一吹口哨大家立即集合,不过这次集合大家都站成了一排,然后老师说向右看齐,这时每个人只能看到右侧比自己矮的人头,如果突然出现一个高于或等于自己身高的同学,那么这名同学以及其右侧的同学将会被挡住。那么,问题来了,现给定所有同学的身高(假设体育课大家修炼了一种神秘技能,改变了自己的身高,(身高最大值为2*106),要求每个人能往右侧看到的人数之和(建议使用long long存储)。
输入
输入包括两行
第一行是人数N(2<=N <= 2*106)
第二行包括N个数字 表示N个同学的身高
输出
输出一个整数,表示所有同学往右侧看到的同学之和
1.1 思路
单调栈的思想运用,从左往右扫描
if 栈为空,或者栈顶元素大于当前元素
当前元素进栈。
else if 当前元素大于栈顶元素,
n = 栈顶元素对应的同学能看到的同学数,就是当前同学的编号减去栈顶同学编号再减去1,
sum += n (将这个值累加到sum)
在同学向右看的队列的最后一个同学后面再插入一个同学,假设此同学是所有同学中最高的。保证每个同学都能从栈里面出来。
1.2 java代码(在最大矩形面积的代码基础上改)
import java.util.Stack;
import java.math.BigInteger;
public class Main {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
float[] array = {1.54f, 1.32f, 1.87f, 1.54f, 1.32f,
1.76f, 1.32f, 1.62f, 1.94f, 1.89f,
1.36f, 1.35f, 1.87f, 1.57f, 1.12f,
1.87f, 1.32f, 1.82f, 1.74f, 1.80f,
1.39f, 1.29f, 1.45f, 1.82f, 1.29f, 9999f};
// 9999f即为哨兵学生, 假设他的身高比所有人都高
System.out.print("学生的身高:");
for(float e: array) System.out.print(e + " ");
BigInteger sum = sum_count(array);
System.out.println("\\n所有人右看齐人数之和:" + sum);
}
public static BigInteger sum_count(float[] array){
BigInteger sum = new BigInteger("0");
int len = array.length;
Stack<Integer> s = new Stack<Integer>();
for(int i=0; i<len; i++){
if(!s.isEmpty() && array[i] < s.peek()) s.push(i);
else {
while(!s.isEmpty() && array[i] >= s.peek()){
int top = s.pop();
sum = sum.add(new BigInteger((i-top-1)+""));
}
s.push(i);
}
}
return sum;
}
}
1.3 结果
题目2 求任意给定数组的逆序对总数
数据量10^6 (利用归并排序的思想)
2.1 思路
- 归并排序思想
- 在归并排序中,归并操作时,在每次右半部的数小于左半部某个数i时,逆序对count进行累加一次,并将值返回
2.2 Java代码
public class Main {
public static void main(String[] args) {
int[] array= {2, 3, 32, 5, 83, 9, 23, 4, 53, 4, 3, 2, 1, 2, 4, 7, 86, 21};
System.out.print("Array:");
for(int e: array) System.out.print(e + " ");
System.out.println("\\nInversion counts:" + inversion_count(array));
System.out.println("Sorted array:" + java.util.Arrays.toString(array));
}
public static int inversion_count(int [] array) {
if(array.length<=0) return 0;
return merge_sort(array,0,array.length-1);
}
public static int merge_sort(int[] array,int lo,int hi){
if(lo>=hi) return 0;
int mid=(lo+hi) >> 1;
int lnums=merge_sort(array,lo,mid);
int rnums=merge_sort(array,mid+1,hi);
return lnums+rnums+merge(array,lo,mid,hi);
}
public static int merge(int[] array, int lo, int mid ,int hi){
int[] temp = new int[hi-lo+1];
int count = 0;
int i = lo, j = mid+1, t = 0;
while( i<=mid || j<=hi ){
if( i>mid && j<=hi ){
temp[t++] = array[j++]; continue;
}else if(i<=mid && j>hi){
temp[t++] = array[i++]; continue;
}
if(array[i] > array[j]){
temp[t++] = array[j++];
count += mid-i+1;
}else {
temp[t++] = array[i++];
}
}
for(i=lo; i<=hi; i++)
array[i] = temp[i-lo];
return count;
}
}