劍指offer----數組篇

面試題03.數組中重複的數字

在這裏插入圖片描述

安安思路1:兩次遍歷

時間複雜度O(n^2)

//用C語言寫出現了超時的問題
int findRepeatNumber(int* nums, int numsSize){
    for(int i = 0; i < numsSize; i++){
        for(int j = i+1; j < numsSize;j++){
            //printf("nums[%d]=%d, nums[%d]=%d\n", i, nums[i], j, nums[j]);
            if(nums[i] == nums[j]){
                return nums[i]; 
            }
        }
    }
    return 0;
}
//java
class Solution {
    public int findRepeatNumber(int[] nums) {
        for(int i = 0; i < nums.length; i++){
            for(int j = i+1; j < nums.length;j++){
                if(nums[i] == nums[j]){
                    return nums[i]; 
                }
            }
        }
        return 0;
    }
}

安安思路2:哈希表(字典存儲)

時間複雜度O(n)

#python
class Solution:
    def findRepeatNumber(self, nums: List[int]) -> int:
        dict1 = {}

        for i in range(len(nums)):
            if nums[i] in dict1:
                dict1[nums[i]] += 1
            else:
                dict1[nums[i]] = 1
        #print(dict1)

        for (k,v) in dict1.items():
            if v > 1:
                return k;

安安思路2改進:哈希表(字典存儲)

時間複雜度O(n)

# python
# 由於題目要求任意一個重複的,所以遇到重複的直接返回就可以了
class Solution:
    def findRepeatNumber(self, nums: List[int]) -> int:
        dict1 = {}

        for i in range(len(nums)):
            if nums[i] in dict1:
                return nums[i]
            else:
                dict1[nums[i]] = 1
        #print(dict1)

官方題解:遍歷數組

在這裏插入圖片描述

//java
class Solution {
    public int findRepeatNumber(int[] nums) {
        Set<Integer> set = new HashSet<Integer>();
        int repeat = -1;
        for (int num : nums) {
            if (!set.add(num)) {
                repeat = num;
                break;
            }
        }
        return repeat;
    }
}

在這裏插入圖片描述

面試題04.二維數組中的查找

在這裏插入圖片描述

安安思路:暴力法

//java
class Solution {
    public boolean findNumberIn2DArray(int[][] matrix, int target) {
        for(int i = 0; i < matrix.length; i++){
            for(int j = 0; j < matrix[i].length; j++){
                //System.out.println(matrix[i][j]+" ");
                if(matrix[i][j] == target){
                    return true;
                }
            }
        }
        //System.out.println();
        return false;
    }
}
//java
class Solution {
    public boolean findNumberIn2DArray(int[][] matrix, int target) {
        for(int[] arr:matrix){  //int[]二維數組中元素的類型, arr迭代變量, matrix二維組的名稱
            for(int i:arr){ //int,一維數組中元素的類型,i,迭代變量,arr,一維數組的名稱
                //System.out.print(i+"\t");
                if(i == target){
                    return true;
                }
            }
        }
        return false;
    }
}
//java 
//如果該行某值大於target,直接查找下一行
class Solution {
    public boolean findNumberIn2DArray(int[][] matrix, int target) {
        for(int i = 0; i < matrix.length; i++){
            for(int j = 0; j < matrix[i].length; j++){
                if(matrix[i][j] == target){
                    return true;
                }else if(matrix[i][j] > target){
                    continue;
                }
            }
        }
        //System.out.println();
        return false;
    }
}

官方題解:線性查找

在這裏插入圖片描述

//java
class Solution {
    public boolean findNumberIn2DArray(int[][] matrix, int target) {
        if(matrix.length == 0 ){  //[]
            return false;
        }
        int i = 0;
        int j = matrix[i].length-1;

        while(i < matrix.length && j >= 0 ){
            //System.out.println(matrix[i][j]);
            if(matrix[i][j] == target){
                return true;
            }else if(matrix[i][j] > target){
                j--;
            }else{
                i++;
            }            
        }

        //System.out.println();
        return false;
    }
}

在這裏插入圖片描述

面試題21.調整數組順序使奇數位於偶數前面

在這裏插入圖片描述

安安思路:雙指針

//java 2020.3.28 anan 雙指針

class Solution {
    public int[] exchange(int[] nums) {
        int left = 0;
        int right = nums.length-1;

        while(left < right){
            while(left< right && nums[left] % 2 != 0){  //遇到奇數了, 加加
                left++;
            }

            while(left < right && nums[right] % 2 == 0){
                right--;
            }

            int tmp = nums[left];
            nums[left] = nums[right];
            nums[right] = tmp;
        }

        return nums;
    }
}

同類型問題擴展 解耦 lambda表達式

在這裏插入圖片描述

在這裏插入圖片描述
在這裏插入圖片描述
Lambda 表達式,也可稱爲閉包,它是推動 Java 8 發佈的最重要新特性。
Lambda 允許把函數作爲一個方法的參數(函數作爲參數傳遞進方法中)。
使用 Lambda 表達式可以使代碼變的更加簡潔緊湊。

//java

class Solution {
    public int[] exchange(int[] nums) {
        return mainPart(nums, isOdd);    //只需修改此處的函數即可實現        
    }

    public int[] mainPart(int[] nums, JudgeFunction judgeFunction){
        int left = 0;
        int right = nums.length-1;

        while(left < right){
            while(left< right && judgeFunction.judge(nums[left]))   left++;            
            while(left < right && (!judgeFunction.judge(nums[right])))  right--;            
            int tmp = nums[left];
            nums[left] = nums[right];
            nums[right] = tmp;
        }
        return nums;
    }

    interface JudgeFunction {
        boolean judge(int num);
    }

    JudgeFunction isOdd = (int num) -> (num%2)!=0;   //判斷奇偶性  //要求奇數位於偶數前面
    JudgeFunction isNegative = (int num) -> (num < 0);   //負數位於非負數前面
    JudgeFunction isThreeTimes = (int num) -> (num%3 == 0);   //能被3整除的位於不能被3正常的前面
    
}

面試題29.順時針打印矩陣(54)

在這裏插入圖片描述

安安思路:遞歸

//java  anan 2020.3.28
class Solution {
    int[] res;
    int index;
    boolean[][] visited;
    int rows;
    int cols;
    int[][] matrix;

    public int[] spiralOrder(int[][] matrix) {
        if(matrix.length == 0) return new int[0];
        
        //初始化
        rows = matrix.length;
        cols = matrix[0].length;
        res = new int[rows*cols];
        index = -1;
        visited = new boolean[rows][cols];
        this.matrix = matrix;

        move(0, 0);
        return res;
    }

    public void move(int x, int y){
        if((x >= 0 && x<= rows-1 && y >= 0 && y <= cols-1 && visited[x][y] == false) == false)   return ;
        visited[x][y] = true;
        res[++index] = matrix[x][y];
        if(y < cols/2){   //位於矩陣的左半部分
            move(x, y-1); //左
            move(x-1, y); //上
            move(x, y+1); //右
            move(x+1, y); //下
        }else{            //位於矩陣的右半部分
            move(x, y+1); //右
            move(x+1, y); //下
            move(x, y-1); //左
            move(x-1, y); //上
        }
    }
}

官方解法1:模擬

在這裏插入圖片描述

//java
class Solution {
    public List<Integer> spiralOrder(int[][] matrix) {
        List ans = new ArrayList();
        if (matrix.length == 0) return ans;
        int R = matrix.length, C = matrix[0].length;
        boolean[][] seen = new boolean[R][C];
        int[] dr = {0, 1, 0, -1};
        int[] dc = {1, 0, -1, 0};
        int r = 0, c = 0, di = 0;
        for (int i = 0; i < R * C; i++) {
            ans.add(matrix[r][c]);
            seen[r][c] = true;
            int cr = r + dr[di];
            int cc = c + dc[di];
            if (0 <= cr && cr < R && 0 <= cc && cc < C && !seen[cr][cc]){
                r = cr;
                c = cc;
            } else {
                di = (di + 1) % 4;
                r += dr[di];
                c += dc[di];
            }
        }
        return ans;
    }
}

作者:LeetCode
鏈接:https://leetcode-cn.com/problems/spiral-matrix/solution/luo-xuan-ju-zhen-by-leetcode/
來源:力扣(LeetCode)
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。

官方解法2:按層模擬(劍指offer)

在這裏插入圖片描述

//java
class Solution {
    public int[] spiralOrder(int[][] matrix) {
        if(matrix.length == 0)  return new int[0];

        int rows = matrix.length;
        int cols = matrix[0].length;
        int x1 = 0, y1 = 0;  //左上角
        int x2 = rows-1, y2 = cols-1;  //右下角
        int[] res = new int[rows*cols];
        int index = -1;

        while(index < rows*cols && x1<=x2 && y1<=y2){
            for(int x=x1, y=y1; y <= y2; y++)  res[++index] = matrix[x][y]; //右 算上右上角
            for(int x=x1+1, y=y2; x <= x2; x++)  res[++index] = matrix[x][y]; //下 算上右下角
            if(x1 < x2 && y1 < y2){
                for(int x=x2, y=y2-1; y > y1; y--)  res[++index] = matrix[x][y]; //左 不算左下角
                for(int x=x2, y=y1; x > x1; x--)  res[++index] = matrix[x][y]; //上 不算左上角
            }            
            x1++;  y1++;
            x2--;  y2--;
            System.out.println(x1+ " " + y1 + " " + x2 + " " + y2);
        }
        
        return res; 

    }

}

面試題40.最小的k個數

在這裏插入圖片描述

安安 O(nlogn)

//java
class Solution {
    public int[] getLeastNumbers(int[] arr, int k) {
        Arrays.sort(arr);
        return Arrays.copyOfRange(arr, 0, k);
    }
}
//[3,2,1,1]   k=2   輸出:[1,1]

參考題解
在這裏插入圖片描述

官方1:堆O(nlogK) (劍指offer)

(leetcode官方)我們用一個大根堆實時維護數組的前 k 小值。首先將前 k 個數插入大根堆中,隨後從第 k+1個數開始遍歷,如果當前遍歷到的數比大根堆的堆頂的數要小,就把堆頂的數彈出,再插入當前遍歷到的數。最後將大根堆裏的數存入數組返回即可。

//java anan 2020.3.30
//獲取最大的k個值  小根堆
//獲取最小的k個值  大根堆
class Solution {
    public int[] getLeastNumbers(int[] arr, int k){  
        if(k == 0)  return new int[0];

        Queue<Integer> q = new PriorityQueue<>(k, new Comparator<Integer>() {
            public int compare(Integer i1, Integer i2) {
                    return i2-i1;
                }
            });

        for (int i = 0; i < k; i++)  q.add(arr[i]);
        for (int i = k; i < arr.length; i++) {
            if(arr[i] < q.peek()){
                q.poll();
                q.add(arr[i]);
            }
        }

        Object[] resTmp = q.toArray();
        int[] res = new int[k];
        for(int i = 0; i < k; i++){
            res[i] = (Integer)resTmp[i];
        }

// 將堆中的元素存入數組  其他同學的寫法
//    int[] res = new int[heap.size()];
//    int j = 0;
//    for (int e : heap) {
//        res[j++] = e;
//    }
//PriorityQueue的iterator()不保證以任何特定順序遍歷隊列元素。但是我們也不需要順序,所以直接遍歷就可以了
        return res;
    }
}
//[3,2,1,1]   k=2   輸出:[1,1]

作者:aanmunyeon
鏈接:https://leetcode-cn.com/problems/zui-xiao-de-kge-shu-lcof/solution/topkwen-ti-javada-gen-dui-shi-xian-by-aanmunyeon/
來源:力扣(LeetCode)
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。

官方2:快速選擇思想O(n) (劍指offer) 必須修改數組

在這裏插入圖片描述
在這裏插入圖片描述

//java
class Solution {
    public int[] getLeastNumbers(int[] arr, int k){  //先獲取最大的k個值  小根堆
        if(k == 0)  return new int[0];
        if(k == arr.length)  return arr;

        partitionArray(arr, k, 0, arr.length-1);
        int[] res = new int[k];
        res = Arrays.copyOf(arr, k);
        return res;
    }

    public static void partitionArray(int[] arr, int k, int low, int high){
        int m = partition(arr, low, high);
       
        if(m == k){
            return ;
        }else if(m < k){
            partitionArray(arr, k, m+1, high);
        }else{
            partitionArray(arr, k, low, m-1);
        }
    }

    //快排的partition函數
    public static int partition(int[] array, int low, int high){
        int base = array[low];
        int i = low;
        int j = high;
        while(i < j){
            while(array[j] > base && i < j) j--;
            while(array[i] <= base && i < j) i++;
            swap(array, i, j);
            //System.out.println(i + " " + j + " " + Arrays.toString(array));
        }
        swap(array, low, j);
        //System.out.println(i + " " + j + " " + Arrays.toString(array));
        return j;
    }

    public static void swap(int[] a, int i, int j){
        int tmp = a[i];  
        a[i] = a[j];
        a[j] = tmp;
    }
}
//[3,2,1,1]   k=2   輸出:[1,1]

在這裏插入圖片描述

面試題39.數組中出現次數超過一半的數字(169)

在這裏插入圖片描述

法1:哈希表

法2:數組排序法(劍指offer) O(n)

直接調用函數排序的時間複雜度爲O(nlogn)
利用面試題40的苦熬蘇選擇思想 時間複雜度可變爲O(n)

法3:摩爾投票法(劍指offer) O(n)

題解參考
在這裏插入圖片描述

//java  anan 2020.3.30
class Solution {
    public int majorityElement(int[] nums) {
        //統計每個數字出現的次數
        Map<Integer, Integer> map = new HashMap<>();
        for(int num: nums){
            if(map.containsKey(num)){
                map.put(num, map.get(num)+1);
            }else{
                map.put(num, 1);
            }
        }
        //System.out.println(map);

        //找到出現次數最多的元素
        Set<Integer> set = map.keySet();
        int max = Integer.MIN_VALUE;
        for(int i: set){
            if(map.get(i) > nums.length/2)
            return i;
        }

        return 0;
    }
}

面試題42.連續子數組的最大和(53)

在這裏插入圖片描述
官方解答

法1:DP O(n) (劍指offer)

在這裏插入圖片描述

法2:分治法 O(nlogn)

分治法思路之前看不明白
這篇博客講的挺清楚的 看懂啦 開心
該博客

//java anan模仿着寫的
class Solution {
    public int maxSubArray(int[] nums) {
        int n = nums.length;
        if(n == 0)  return 0;

        return partition(nums, 0, n-1);
    }

    public static int partition(int[] nums, int left, int right){    
        if(left == right)      return nums[left];
        
        int mid = (left+right)/2;

        //左邊序列和右邊序列的最大子序和
        int maxSumLeft = partition(nums, left,mid);
        int maxSumRight = partition(nums, mid+1, right);

        //包含左邊序列最後一個元素的最大序列和
        int maxSumLeftBorder = nums[mid];
        int sumLeftBorder = nums[mid];
        for(int i = mid-1; i >= left; i--){
            sumLeftBorder += nums[i];
            maxSumLeftBorder = Math.max(maxSumLeftBorder, sumLeftBorder);
        }

        //包含右邊序列第一個元素的最大序列和
        int maxSumRightBorder = nums[mid+1];
        int sumRightBorder = nums[mid+1];
        for(int i = mid+2; i <= right; i++){
            sumRightBorder += nums[i];
            maxSumRightBorder = Math.max(maxSumRightBorder, sumRightBorder);
        }
        int maxSumCross = maxSumLeftBorder+maxSumRightBorder;

        int maxOfThree = ((maxSumLeft > maxSumRight) ? maxSumLeft : maxSumRight) > maxSumCross ? ((maxSumLeft > maxSumRight) ? maxSumLeft : maxSumRight) : maxSumCross;
        //System.out.println(maxSumLeft + " " + maxSumRight + " " + maxSumCross + " " + maxOfThree);

        return maxOfThree;        
    }
}

面試題47.禮物的最大價值(矩陣)(64)

在這裏插入圖片描述
基本同leetcode第64題

法1:DP二維

//java anan 2020.3.30
class Solution {
    public int maxValue(int[][] grid) {
        if(grid.length == 0)  return 0;

        int rows = grid.length;
        int cols = grid[0].length;
        int[][] dp = new int[rows][cols];

        for(int i = 0; i < rows; i++){
            for(int j = 0; j < cols; j++){
                if(i == 0 && j == 0) dp[i][j] = grid[0][0];
                else if(i == 0)  dp[i][j] = dp[i][j-1]+grid[i][j];
                else if(j == 0)  dp[i][j] = dp[i-1][j]+grid[i][j];
                else dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1])+grid[i][j];
            }
        }
        return dp[rows-1][cols-1];
    }
}
//java  參考自己之前寫的代碼進行了代碼改進
class Solution {
    public int maxValue(int[][] grid) {
        if(grid.length == 0)  return 0;
        
        int rows = grid.length;
        int cols = grid[0].length;
        int[][] dp = new int[rows][cols];
        dp[0][0] = grid[0][0];

        for(int i = 0; i < rows; i++){
            for(int j = 0; j < cols; j++){
                if(i != 0 || j != 0){
                    dp[i][j] = Math.max(  (i >=1 ? dp[i-1][j] : Integer.MIN_VALUE), (j >= 1 ? dp[i][j-1] : Integer.MIN_VALUE )  ) + grid[i][j];
                }
            }
        }
        return dp[rows-1][cols-1];
    }
}

法2:DP(一維)

//java  空間優化
class Solution {
    public int maxValue(int[][] grid) {
        if(grid.length == 0)  return 0;
        
        int rows = grid.length;
        int cols = grid[0].length;
        int[] dp = new int[cols];
        dp[0] = grid[0][0];

        for(int i = 0; i < rows; i++){
            for(int j = 0; j < cols; j++){
                if(i != 0 || j != 0){
                    dp[j] = Math.max(  (i >=1 ? dp[j] : Integer.MIN_VALUE), (j >= 1 ? dp[j-1] : Integer.MIN_VALUE )  ) + grid[i][j];
                }
            }
        }
        return dp[cols-1];
    }
}

法3:DP(不開闢新數組)

//java 不開闢數組空間 在原數組上操作
class Solution {
    public int maxValue(int[][] grid) {
        if(grid.length == 0)  return 0;
        
        int rows = grid.length;
        int cols = grid[0].length;

        for(int i = 0; i < rows; i++){
            for(int j = 0; j < cols; j++){
                if(i != 0 || j != 0){
                    grid[i][j] = Math.max(  (i >=1 ? grid[i-1][j] : Integer.MIN_VALUE), (j >= 1 ? grid[i][j-1] : Integer.MIN_VALUE )) + grid[i][j];
                }
            }
        }
        return grid[rows-1][cols-1];
    }
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章