題目:統計一個數字在排序數組中出現的次數。例如輸入排序數組{1,2,3,3,3,3,4,5}和數字3,由於3在這個數組中出現了4次,因此輸出4。
暴力解法的時間復雜度為O(n),還有更優的解法,運用二分查找,時間復雜度為O(logn):
1.先找出第一次出現的下標值,設left,mid,right分別代表數組的起始,中間,結束的下標。
若數組中間的數a[mid]大於k,則right = mid -1;
若數組中間的數a[mid]小於k,則left = mid+1;
若數組中間的數a[mid]等於k,判斷a[mid-1] 是否等於k,若不等於,說明是第一次出現的下標,返回mid下標;若等於,則說明第一次出現的下標還在mid的左邊,right = mid -1;
遞歸重復以上過程。
2.再找出最后出現的下標,原理同上。
參考代碼:
package test; import org.junit.Test; public class Solution { public int getNumOfK(int[] a, int k) { if (a == null || a.length == 0) return 0; int first = getFirstK(a, 0, a.length - 1, k); int last = getLastK(a, 0, a.length - 1, k); if (first > -1 && last > -1) return last - first + 1; return 0; } private int getFirstK(int[] a, int left, int right, int k) { if (left > right) return -1; int mid = (left + right) / 2; int midData = a[mid]; // 中間的數等於k if (midData == k) { //mid的前一個數不是k,說明是第一個出現的數 if (mid > 0 && a[mid - 1] != k || mid == 0) return mid; else //不是第一個出現的數,第一個出現的數再數組的左邊 right = mid - 1; // 中間的數大於k,說明在數組的左邊 } else if (midData > k) right = mid - 1; else // 中間的數小於k,說明在數組的右邊 left = mid + 1; return getFirstK(a, left, right, k); } private int getLastK(int[] a, int left, int right, int k) { if (left > right) return -1; int mid = (left + right) / 2; int midData = a[mid]; if (midData == k) { if (mid < a.length - 1 && a[mid + 1] != k || mid == a.length - 1) return mid; else left = mid + 1; } else if (midData > k) right = mid - 1; else left = mid + 1; return getLastK(a, left, right, k); } @Test public void testSolution() { int[] a = { 1, 2, 3, 3, 3, 3, 4, 5 }; int k = 3; System.out.println(getNumOfK(a, k));//4 } }