數組、矩陣類算法題

一.移動零

力扣傳送門
給定一個數組 nums,編寫一個函數將所有 0 移動到數組的末尾,同時保持非零元素的相對順序。

示例:
輸入: [0,1,0,3,12]
輸出: [1,3,12,0,0]

說明:
必須在原數組上操作,不能拷貝額外的數組。
儘量減少操作次數。

    /*
    * 把數組中的 0 移到末尾
    * */
    public void moveZeroes(int[] nums) {
        if (nums == null || nums.length == 0) return;
        int n = nums.length;
        int curIndex = 0;
        for (int i = 0; i < n; i++) {
            if (nums[i] != 0) nums[curIndex++] = nums[i];
        }
        while (curIndex < n) {
            nums[curIndex++] = 0;
        }
        return;
    }

二.改變矩陣維度

力扣傳送門
在MATLAB中,有一個非常有用的函數 reshape,它可以將一個矩陣重塑爲另一個大小不同的新矩陣,但保留其原始數據。
給出一個由二維數組表示的矩陣,以及兩個正整數r和c,分別表示想要的重構的矩陣的行數和列數。
重構後的矩陣需要將原始矩陣的所有元素以相同的行遍歷順序填充。
如果具有給定參數的reshape操作是可行且合理的,則輸出新的重塑矩陣;否則,輸出原始矩陣。

在這裏插入圖片描述

    /*
    * 重塑矩陣
    * */
    public int[][] matrixReshape(int[][] nums, int r, int c) {
        if (nums == null || nums.length == 0) return null;
        int n = nums.length;
        int m = nums[0].length;
        if (n * m != r * c) return null;
        int newNums[][] = new int[r][c];
        int row = 0, col = 0;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (col == c) {
                    row++;
                    col = 0;
                }
                newNums[row++][col++] = nums[i][j];
            }
        }
        return newNums;
    }

三.找出數組中最長的連續 1

力扣傳送門

    /*
    * 找出數組中最長的連續 1
    * 給定一個二進制數組, 計算其中最大連續1的個數。
    * */
    public int findMaxConsecutiveOnes(int[] nums) {
        int curlen = 0;
        int maxlen = 0;
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] == 1) curlen++;
            else curlen = 0;
            maxlen = Math.max(maxlen, curlen);
        }
        return maxlen;
    }

四.有序矩陣查找

力扣傳送門

    /*
    * 有序矩陣查找
    * */
    public boolean searchMatrix(int[][] matrix, int target) {
        if (matrix == null || matrix.length == 0) return false;
        int m = matrix.length;
        int n = matrix[0].length;
        int row = 0;
        int col = n - 1;
        while (row < m && col >= 0) {
            if (matrix[row][col] == target) {
                return true;
            } else if (matrix[row][col] > target) {
                col--;
            } else {
                row++;
            }
        }
        return false;
    }

五.一個數組元素在 [1, n] 之間,其中一個數被替換爲另一個數,找出重複的數和丟失的數

力扣傳送門

    public int[] findErrorNums(int[] nums) {
        if (nums == null || nums.length == 0) return null;
        int n = nums.length;
        int result[] = new int[2];
        for (int i = 0; i < n; ) {
            if (i != nums[i] - 1) {
                if (nums[nums[i] - 1] == nums[i]) {
                    result[0] = nums[i];
                    i++;
                } else {
                    swap(nums, i, nums[i] - 1);
                }
            } else {
                i++;
            }
        }
        for (int i = 0; i < n; i++) {
            if (nums[i] - 1 != i) {
                result[1] = i + 1;
                break;
            }
        }
        return result;
    }

六.優美的排列 II —數組相鄰差值的個數

題目描述:數組元素爲 1~n 的整數,要求構建數組,使得相鄰元素的差值不相同的個數爲 k。
力扣傳送門
解法一:dfs超時

 public int[] constructArray(int n, int k) {//方法一:dfs超時
        boolean book[] = new boolean[n + 1];
        int result[] = new int[n];
        HashSet<Integer> set = new HashSet<>();
        dfs(book, result, 0, set, n, k);
        return res;
    }

    int res[] = null;

    public void dfs(boolean book[], int result[], int curIndex, HashSet<Integer> set, int n, int k) {
        if (curIndex == n && set.size() == k) {
            res = new int[n];
            for (int i = 0; i < n; i++) {
                res[i] = result[i];
            }
            return;
        }
        if (curIndex > n || set.size() > k) return;//剪枝
        for (int i = 1; i <= n; i++) {
            if (book[i]) continue;
            book[i] = true;
            result[curIndex] = i;
            if (curIndex > 0) set.add(Math.abs(result[curIndex - 1] - i));
            dfs(book, result, curIndex + 1, set, n, k);
            if (curIndex > 0) set.remove(Math.abs(result[curIndex - 1] - i));
            book[i] = false;
        }
    }

解法二:不斷反轉
若n=8初始狀態
1 2 3 4 5 6 7 8
k=1------ | 1 2 3 4 5 6 7 8 (不翻轉,直接返回)
k=2------ 1 | 8 7 6 5 4 3 2
k=3------ 1 8 | 2 3 4 5 6 7
k=4------ 1 8 2 | 7 6 5 4 3

    public int[] constructArray2(int n, int k) {//方法二:不斷反轉
        int a[] = new int[n];
        for (int i = 0; i < n; i++) a[i] = i + 1;
        int cur = 1;
        for (int j = 0; j < k - 1; j++) {
            reverse(a, cur, n - 1);
            cur++;
        }
        return a;
    }

    public void reverse(int a[], int start, int end) {
        while (start < end) {
            int tmp = a[start];
            a[start] = a[end];
            a[end] = tmp;
            start++;
            end--;
        }
    }

七.數組的度

力扣傳送門
給定一個非空且只包含非負數的整數數組 nums, 數組的度的定義是指數組裏任一元素出現頻數的最大值。
你的任務是找到與 nums 擁有相同大小的度的最短連續子數組,返回其長度。
在這裏插入圖片描述
解法一:

    public int findShortestSubArray(int[] nums) {
        if (nums == null || nums.length == 0) return 0;
        int num = -1;//保存目前爲止出現最高頻率的數字
        int maxCount = 0;//保存目前爲止的最高頻率
        int minlen = 1;//保存最高頻率數字的長度
        Map<Integer, Integer> map = new HashMap<>();//保存數字的頻率
        Map<Integer, Integer> mapStart = new HashMap<>();//保存數字的開始位置
        for (int i = 0; i < nums.length; i++) {
            if (!mapStart.containsKey(nums[i])) {//不包含 put
                mapStart.put(nums[i], i);
                map.put(nums[i], 0);
            } else {//包含 計數
                map.put(nums[i], map.get(nums[i]) + 1);
            }
            int count = map.get(nums[i]);
            if (count > maxCount) {//當前數字的頻率大於最高頻率
                num = nums[i];//更新最高頻率數字
                maxCount = count;//更新頻率
                minlen = i - mapStart.get(nums[i]) + 1;//更新最高頻率數字長度
            }
            if (count == maxCount) {//當前數字的頻率等於最高頻率
                int curlen = i - mapStart.get(nums[i]) + 1;
                if (curlen < minlen) {//比較長度,取短的
                    num = nums[i];
                    maxCount = count;
                    minlen = curlen;
                }
            }
        }

        return minlen;
    }

解法二:

    public int findShortestSubArray2(int[] nums) {
        Map<Integer, Integer> leftmap = new HashMap<>();
        Map<Integer, Integer> rightmap = new HashMap<>();
        Map<Integer, Integer> countmap = new HashMap<>();
        int maxCount = 0;
        for (int i = 0; i < nums.length; i++) {
            if (!leftmap.containsKey(nums[i])) {
                leftmap.put(nums[i], i);
            }
            rightmap.put(nums[i], i);
            int curCount = countmap.getOrDefault(nums[i], 0) + 1;
            maxCount = Math.max(maxCount, curCount);
            countmap.put(nums[i], curCount);
        }
        int minlen = nums.length;
        Iterator<Map.Entry<Integer, Integer>> iterator = countmap.entrySet().iterator();//注意map遍歷方式
        while (iterator.hasNext()) {
            Map.Entry<Integer, Integer> entry = iterator.next();
            if (entry.getValue() == maxCount) {
                minlen = Math.min(minlen, rightmap.get(entry.getKey()) - leftmap.get(entry.getKey()) + 1);
            }
        }
        return minlen;
    }

八.對角元素相等的矩陣

力扣傳送門
如果一個矩陣的每一方向由左上到右下的對角線上具有相同元素,那麼這個矩陣是託普利茨矩陣。
給定一個 M x N 的矩陣,當且僅當它是託普利茨矩陣時返回 True。
在這裏插入圖片描述
解法一:

/*
    * 對角元素相等的矩陣
    * */
    public boolean isToeplitzMatrix(int[][] matrix) {
        int n = matrix.length;
        int m = matrix[0].length;
        for (int i = 0; i < n; i++) {
            int x = i, y = 0;
            int num = matrix[i][0];
            while (x < n && y < m) {
                if (matrix[x][y] != num) return false;
                x++;
                y++;
            }
        }
        for (int j = 0; j < m; j++) {
            int x = 0, y = j;
            int num = matrix[0][j];
            while (x < n && y < m) {
                if (matrix[x][y] != num) return false;
                x++;
                y++;
            }
        }
        return true;
    }

解法二:

class Solution {
    public boolean isToeplitzMatrix(int[][] matrix) {
        Map<Integer, Integer> groups = new HashMap();
        for (int r = 0; r < matrix.length; ++r) {
            for (int c = 0; c < matrix[0].length; ++c) {
                if (!groups.containsKey(r-c))
                    groups.put(r-c, matrix[r][c]);
                else if (groups.get(r-c) != matrix[r][c])
                    return False;
            }
        }
        return True;
    }
}

九.嵌套數組

力扣傳送門
索引從0開始長度爲N的數組A,包含0到N - 1的所有整數。找到並返回最大的集合S,S[i] = {A[i], A[A[i]], A[A[A[i]]], … }且遵守以下的規則。

假設選擇索引爲i的元素A[i]爲S的第一個元素,S的下一個元素應該是A[A[i]],之後是A[A[A[i]]]… 以此類推,不斷添加直到S出現重複的元素。

在這裏插入圖片描述
藉助力扣官方題解的一張圖來理解:
在這裏插入圖片描述

    public int arrayNesting(int[] nums) {
        int n = nums.length;
        boolean book[] = new boolean[n];
        int maxLen = 0;
        for (int i = 0; i < n; i++) {
            int tmp = i;
            int count = 0;
            while (!book[tmp]) {
                count++;
                book[tmp] = true;
                tmp = nums[tmp];
            }
            maxLen = Math.max(maxLen, count);
        }
        return maxLen;
    }

十.最多能完成排序的塊—分割數組
力扣傳送門
數組arr是[0, 1, …, arr.length - 1]的一種排列,我們將這個數組分割成幾個“塊”,並將這些塊分別進行排序。之後再連接起來,使得連接的結果和按升序排序後的原數組相同。

我們最多能將數組分成多少塊?
在這裏插入圖片描述

    /*
    * 分割數組
    * 分隔數組,使得對每部分排序後數組就爲有序。
    * */
    public int maxChunksToSorted(int[] arr) {//做法一
        int n = arr.length;
        boolean book[] = new boolean[n];
        HashMap<Integer, Integer> map = new HashMap<>();
        int count = 0;
        int pre = 0;
        for (int i = 0; i < arr.length; i++) {
            book[arr[i]] = true;
            boolean flag = true;
            for (int j = pre; j <= i; j++) {//每遍歷一個arr[i]就判斷,在i位置之前的元素是否都已出現過
                if (!book[j]) flag = false;
            }
            if (flag) {
                pre = i + 1;
                count++;
            }
        }
        return count;
    }

    public int maxChunksToSorted2(int[] arr) {//做法二
        int n = arr.length;
        int right = -1;//標記最右位置
        int count = 0;
        for (int i = 0; i < n; i++) {
            right = Math.max(right, arr[i]);
            if (right == i) count++;
        }
        return count;
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章