仅做个人记录
原始二分法
返回的是index
public int halfSearch(int a[], int s, int e, int key) {
while(s <= e) {
int mid = (s + e)/2;
int m = mid/2;
if(m==key) return mid;
else if(m < key) e = mid-1;
else if(m > key) s = mid+1;
}
return -1;
}
新的需求如下
比如 1 2 3 4 5
给定一个start和end(下面用简称),找到在[s,e]区间内的个数
当然可以for循环走一遍,但是这里的12345已经是有序的了,整个走一遍,效率不高
思路
可以是没找到,如灰色小箭头;可以是找到了,如红色小箭头
所以统一用一个float表示
s和e的位置有这几种情况
为了提升效率,我们可以先求出s,就是横线的左边的箭头位置,s之前的数字就不用检索了
比如12345我们s=3.5,那么我们检索右边的时候,只需要检索45即可了
之后再次用e带进去查找,e右边的将被割舍,最终s和e的距离就是包含区间的距离
最终代码
package toutiao_test; import java.util.*; public class toutiao_2018_1 { public static void main(String args[]) { HashMap<Integer, List<Integer>> mapList = new HashMap<>(); Scanner scanner = new Scanner(System.in); int n = scanner.nextInt(); int[] a = new int[n];//不同用户的不同喜爱度 for (int i = 0; i < n; i++) { a[i] = scanner.nextInt(); if (mapList.containsKey(a[i])) { List<Integer> list = mapList.get(a[i]); list.add(i); } else { List<Integer> list = new ArrayList<>(); list.add(i); mapList.put(a[i], list); } } int q = scanner.nextInt(); for (int i = 0; i < q; i++) { int s = scanner.nextInt() - 1; int e = scanner.nextInt() - 1; int k = scanner.nextInt(); List<Integer> list = mapList.get(k); if (list == null) { System.out.println(0); } else { //拿到s-e区间内的总数 float left = search(list, 0, list.size() - 1, s); int l; if (left < 0) { l = 0; } else { if ((left * 10)%10 == 5) { l = (int) (left + 1); } else { l = (int) left; } } float right = search(list, l, list.size() - 1, e); int count; if (right < l) { count = 0; } else { count = (int) right - l + 1;//! } System.out.println(count); } } } private static float search(List<Integer> list, int s, int e, int val) { if (s > e) { return -999; } float index = -999; while (s <= e) { int mid = (s + e) / 2; int midVal = list.get(mid); if (midVal == val) { return mid; } else if (val < midVal) { e = mid - 1; index = mid - 0.5f; } else { s = mid + 1; index = mid + 0.5f; } } return index; } } //5 //1 2 3 3 5 //3 //1 2 1 //2 4 5 //3 5 3 //5 //1 2 3 3 5 //1 //3 5 3