一、醜數
題目:
/** * 編寫一個程序判斷給定的數是否爲醜數。 * 醜數就是隻包含質因數 2, 3, 5 的正整數。 * * 示例 1: * 輸入: 6 * 輸出: true * 解釋: 6 = 2 × 3 * * 示例 2: * 輸入: 8 * 輸出: true * 解釋: 8 = 2 × 2 × 2 * * 示例 3: * 輸入: 14 * 輸出: false * 解釋: 14 不是醜數,因爲它包含了另外一個質因數 7。 * * 說明: * 1 是醜數。 * 輸入不會超過 32 位有符號整數的範圍: [−2^31, 2^31 − 1]。 */
可以直接根據醜數的判定規則進行判斷,只包含2,3,5這三個質因數,那我就把這三個數除盡看看剩不剩其他的數就好了。
public static boolean method1(int num) {
if (num<1) return false;
while (num%5==0){
num/=5;
}
while (num%3==0){
num/=3;
}
while (num%2==0){
num>>=1;
}
return num == 1;
}
二、消失的數
題目:
/** * 給定一個包含 0, 1, 2, ..., n 中 n 個數的序列,找出 0 .. n 中沒有出現在序列中的那個數。 * * 示例 1: * 輸入: [3,0,1] * 輸出: 2 * * 示例 2: * 輸入: [9,6,4,2,3,5,7,0,1] * 輸出: 8 * * 說明: * 你的算法應具有線性時間複雜度。你能否僅使用額外常數空間來實現? */
一種簡單的解決方法,把數組排序,然後遍歷判斷找出
public static int method1(int[] nums) {
Arrays.sort(nums);
int i=0;
for (;i<nums.length;i++){
if (nums[i]!=i){
return i;
}
}
return i+1;
}
你還可以藉助位運算,一個數異或另一個數兩次等於它本身,一個數異或它自己等於0,0異或任何數等於任何數
public static int method2(int[] nums) {
int res = nums.length;
for (int i = 0; i < nums.length; ++i){
res ^= nums[i];
res ^= i;
}
return res;
}
三、移動零
題目:
/** * 給定一個數組 nums,編寫一個函數將所有 0 移動到數組的末尾,同時保持非零元素的相對順序。 * * 示例: * 輸入: [0,1,0,3,12] * 輸出: [1,3,12,0,0] * * 說明: * 必須在原數組上操作,不能拷貝額外的數組。 * 儘量減少操作次數。 */
第一個想到的就是快慢指針,把快指針掃描到的非0的數字賦值到慢指針的位置,快指針走完就把從慢指針當前所在位置到數組尾全部賦值爲0。
public static void method1(int[] nums) {
int fast = 0, slow = 0, count = 0;
for (; fast < nums.length; fast++) {
if (nums[fast] != 0) {
count++;
if (fast != slow) {
nums[slow] = nums[fast];
}
slow++;
}
}
for (int i = count; i < nums.length; i++) {
nums[i] = 0;
}
}
換一種寫法就是當快指針掃描到的非0的數字就和慢指針爲0的數字交換,我在這裏還加了一個判斷,快慢指針位置不相等,是因爲我交換的操作沒有藉助第三個變量,因爲其中一個數已知,只需要把快指針的數賦值到慢指針上,然後慢指針的數賦值爲0就可以了。
public static void method2(int[] nums) {
int fast = 0, slow = 0;
for (; fast < nums.length; fast++) {
if (nums[fast] != 0) {
if (fast != slow) {
nums[slow] = nums[fast];
nums[fast]=0;
}
slow++;
}
}
}
四、尋找中位數
題目:
/** * 中位數是有序列表中間的數。如果列表長度是偶數,中位數則是中間兩個數的平均值。 * * 例如, * [2,3,4] 的中位數是 3 * [2,3] 的中位數是 (2 + 3) / 2 = 2.5 * * 設計一個支持以下兩種操作的數據結構: * void addNum(int num) - 從數據流中添加一個整數到數據結構中。 * double findMedian() - 返回目前所有元素的中位數。 * * 示例: * addNum(1) * addNum(2) * findMedian() -> 1.5 * addNum(3) * findMedian() -> 2 * * 進階: * 如果數據流中所有整數都在 0 到 100 範圍內,你將如何優化你的算法? * 如果數據流中 99% 的整數都在 0 到 100 範圍內,你將如何優化你的算法? */
你可以在插入時做文章把它在插入時就整理成有序數組,使用二分查找插入,然後找中位數時就分兩種情況,一種是長度爲奇數一種是長度爲偶數,也可以在尋找中位數時做文章,可以使用Arrays.sort來排序數組。
List<Integer> list;
public MedianFinder() {
list = new ArrayList();
}
public void addNum(int num) {
int left = 0;
int right = list.size() - 1;
while (left < right) {
int mid = left + (right - left) / 2;
int val = list.get(mid);
if (val < num) left = mid + 1;
else right = mid;
}
if (list.size() > 0 && num > list.get(list.size() - 1))
list.add(num);
else
list.add(left, num);
}
public double findMedian() {
int len = list.size();
if (len % 2 == 1)
return (double) list.get(len / 2);
else
return list.get(len / 2) / 2.0
+ list.get(len / 2 - 1) / 2.0;
}
還有一種解法就是題目中提到的進階,假設所有的數都在0-100範圍內,那你就可以定義一個長度爲101的數組,存儲所有數字出現的次數,定義一個count變量,在添加數字的時候對其加一,實現計數,這樣就實現了排序和計數,在找中位數時根據總數量進行判斷更改。假設所有的數99%出現在0-100內呢,你就要多定義兩個長度來保存小於0的數出現的次數和大於100的數出現的次數,再找中位數時要注意下標的變化。
private int[] nums=new int[103];
private int count=0;
public MedianFinder() {
}
public void addNum(int num) {
if (num>100){
nums[102]=nums[102]+1;
}else if (num<0){
nums[0]=nums[0]+1;
} else {
nums[num+1]=nums[num+1]+1;
}
count++;
}
public double findMedian() {
int sum=0;
if (count%2==0){
int index=count/2;
for (int i=0;i<103;i++){
sum+=nums[i];
if (sum==index){
return (i+i-1)/2.0;
}else if (sum>index){
return i-1;
}
}
}else {
int index=count/2+1;
for (int i=0;i<103;i++){
sum+=nums[i];
if (sum>=index){
return i-1;
}
}
}
return 0;
}