leetcode演算法題解(Java版)-14-第k小數問題

kissjz發表於2018-05-20

一、第k小數問題

題目描述

There are two sorted arrays A and B of size m and n respectively. Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).

思路

  • 題目要求在O(log(m+n))時間內完成,可以轉換為找到假設兩個陣列合並後的第(m+n)/2小的數。
  • 這裡先忽略奇偶問題,具體實現程式碼中會有不同。先假設A和B中的數都大於k/2,比較A[k/2-1]和B[k/2-1](減1是因為陣列下標從零開始)如果A[k/2-1]

程式碼

public class Solution {
    public double findMedianSortedArrays(int A[], int B[]) {
        //奇偶數不會有影響,最後中位數就是平均值
        int m = A.length,n = B.length;
        int l = (m+n+1)/2;
        int r = (m+n+2)/2;
        
        return (findKthNum(A,B,0,0,l)+findKthNum(A,B,0,0,r))/2.0;
    }
    private double findKthNum(int [] A,int [] B,int Astart,int Bstart,int k){
        int lenA = A.length;
        int lenB = B.length;
        if(Astart>=lenA){
            return B[Bstart+k-1];
        }
        if(Bstart>=lenB){
            return A[Astart+k-1];
        }
        if(k==1){
            return Math.min(A[Astart],B[Bstart]);
        }
        int minA = Integer.MAX_VALUE;
        int minB = Integer.MAX_VALUE;
        if(Astart+k/2-1<A.length){
            //如果這裡超過了A陣列的範圍,那就說明A中有將A、B合併後一半以上的
            //數,也就是說中位數肯定在A中。那後面的minB<minA(MAX_VALUE),就會成立,從而捨棄B中的前一些無關的數
            minA = A[Astart+k/2-1];
        }
        if(Bstart+k/2-1<B.length){
            minB = B[Bstart+k/2-1];
        }
        if(minA<minB){
            return findKthNum(A,B,Astart+k/2,Bstart,k-k/2);
        }
        else{
            return findKthNum(A,B,Astart,Bstart+k/2,k-k/2);
        }
    }
}

二、map對映

題目描述

Given an array of integers, find two numbers such that they add up to a specific target number.
The function twoSum should return indices of the two numbers such that they add up to the target, where index1 must be less than index2. Please note that your returned answers (both index1 and index2) are not zero-based.
You may assume that each input would have exactly one solution.
Input: numbers={2, 7, 11, 15}, target=9
Output: index1=1, index2=2

思路

  • 給一列數,給一個目標值,找出數列中兩個數和為這個值的下標。因為數沒有排序,可以考慮用map來構建數值和下標的對映,更狠一點,在遍歷陣列的同時,用map構建目標值減去當前這個數的值與當前下標的對映,然後對每一個遍歷到的數判斷是否已存在在map中。

程式碼

import java.util.HashMap;

public class Solution {
    public int[] twoSum(int[] numbers, int target) {
        int n = numbers.length;
        int [] res = new int [2];
        HashMap<Integer,Integer> map = new HashMap<Integer,Integer>();
        for(int i=0 ;i<n;i++){
            if(map.containsKey(numbers[i])){
                res[0]=map.get(numbers[i])+1;
                res[1]=i+1;
                break;
            }
            else{
                map.put(target-numbers[i],i);
            }
        }
        return res;
    }
}

三、動態規劃

題目描述

You are climbing a stair case. It takes n steps to reach to the top.
Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top?

思路

  • 題目提示了用動態規劃來解,那自然想到從step 1,2,3,.。於是慢慢推了看看,看是否能得到狀態轉移方程。寫了幾個,發現:dp[i]=dp[i-1]+dp[i-2];

程式碼

public class Solution {
    public int climbStairs(int n) {
        int [] dp = new int[n+2];
        dp[1]=1;
        dp[2]=2;
        for(int i=3;i<=n;i++){
            dp[i]=dp[i-1]+dp[i-2];
        }
        return dp[n];
    }
}

//優化一下空間複雜度
public class Solution {
    public int climbStairs(int n) {
        if(n<=2){
            return n;
        }
        int one_step_before=2;
        int two_step_before=1;
        for(int i=3;i<=n;i++){
            int cur = one_step_before+two_step_before;
            two_step_before = one_step_before;
            one_step_before = cur;
        }
        return one_step_before;
    }
}


相關文章