1. 程式人生 > >【LeetCode題解】陣列Array

【LeetCode題解】陣列Array

1. 陣列

直觀地看,陣列(Array)為一個二元組<index, value>的集合——對於每一個index,都有一個value與之對應。C語言中,以“連續的儲存單元”實現陣列:

int arr[5], *p_arr[5];

陣列提供以\(O(1)\)的複雜度訪問元素,下標從0開始。但是,陣列的插入、刪除操作卻非常耗時,因為這涉及到了元素間的移動。

常見的矩陣,可用二維陣列表示。二維陣列本質上是一個一維陣列,其中每個行單元也是一個一維陣列,比如,二維陣列int x[3][5]的儲存結構如下:

從上圖可以看出,x共有4塊儲存區,一塊用於用以存放行單元指標(x[0:2]),另外三塊用於存放每一個行單元對應的一維陣列。因此,x是一個長度為3的一維陣列,而行單元x[0]又是一個長度為5的一維陣列。

2. 題解

LeetCode題目 歸類
26. Remove Duplicates from Sorted Array 刪除
80. Remove Duplicates from Sorted Array II 刪除
27. Remove Element 刪除
88. Merge Sorted Array 合併
268. Missing Number 查詢
41. First Missing Positive 查詢
287. Find the Duplicate Number 查詢
189. Rotate Array 旋轉
54. Spiral Matrix 矩陣遍歷
59. Spiral Matrix II
48. Rotate Image 矩陣旋轉
73. Set Matrix Zeroes

26. Remove Duplicates from Sorted Array
移除陣列中重複的元素,由於資料是有序的,所以重複元素一定是相鄰的。用兩個pointers,一個用於新陣列生成,一個用於遍歷原陣列:

public int removeDuplicates(int[] nums) {
  if (nums.length == 0) return 0;
  int i = 1;
  for (int j = 1; j < nums.length; j++) {
    if (nums[j] != nums[i - 1])
      nums[i++] = nums[j];
  }
  return i;
}

80. Remove Duplicates from Sorted Array II
上一問題的變種,新陣列中最多允許兩個重複元素。

public int removeDuplicates(int[] nums) {
  if (nums.length == 0) return 0;
  int i = 2;
  for (int j = 2; j < nums.length; j++) {
    if (nums[j] != nums[i - 2])
      nums[i++] = nums[j];
  }
  return i;
}

27. Remove Element
移去陣列中出現的指定元素。也是用兩個pointers遍歷陣列,從頭尾兩端往中間移動交換:

public int removeElement(int[] nums, int val) {
  int i = 0, j = nums.length - 1;
  while (i <= j) {
    while (j >= i && nums[j] == val) j--; // reduce array size
    if (i <= j && nums[i] == val) {
      nums[i] = nums[j]; // swap between the current and the last
      j--; // reduce array size
    }
    i++;
  }
  return j + 1;
}

88. Merge Sorted Array
合併兩個有序陣列,從後往前開始合併:

public void merge(int[] nums1, int m, int[] nums2, int n) {
  int i = m - 1, j = n - 1, k = m + n - 1;
  while (j >= 0) {
    if (i >= 0 && nums1[i] > nums2[j])
      nums1[k--] = nums1[i--];
    else
      nums1[k--] = nums2[j--];
  }
}

268. Missing Number
數的範圍[0,n],找出缺失的數。思路:目標和n*(n+1)/2減去陣列之和即為缺失數。

public int missingNumber(int[] nums) {
  int sum = 0, n = nums.length;
  for (int i : nums) {
    sum += i;
  }
  return n * (n + 1) / 2 - sum;
}

41. First Missing Positive
找出缺失的第一個正數,陣列的正數範圍在[1,n]。將正數i放在i-1位置上,然後找出缺失數。

public int firstMissingPositive(int[] nums) {
  for (int i = 0; i < nums.length; i++) {
    while (nums[i] > 0 && nums[i] <= nums.length && nums[i] != nums[nums[i] - 1])
      swap(nums, i, nums[i] - 1);
  }
  for (int i = 0; i < nums.length; i++) {
    if (nums[i] != i + 1)
      return i + 1;
  }
  return nums.length + 1;
}

private void swap(int[] A, int a, int b) {
  int temp = A[a];
  A[a] = A[b];
  A[b] = temp;
}

287. Find the Duplicate Number
從陣列中找出重複數,且陣列中的數的範圍在[1,n],且只有一個數重複,重複次數>=2。解決思路:將陣列看作一個移動連結串列,按照index=a[index]方式進行移動;那麼重複元素會使之成為一個有環的連結串列,並且重複的元素為環的開始。故可用快慢兩個指標來解決。

public int findDuplicate(int[] nums) {
  int slow = nums[0], fast = nums[nums[0]];
  while (slow != fast) { // find the entry point where slow and fast meet
    slow = nums[slow];
    fast = nums[nums[fast]];
  }
  for (fast = 0; slow != fast; ) { // find the entry point where the cycle begins
    slow = nums[slow];
    fast = nums[fast];
  }
  return slow;
}

189. Rotate Array
指定一個數組截斷點,將左子陣列拼接到右子陣列後。解決思路:現將整個陣列逆序,再將逆序後的左部分逆序、右部分逆序。

public void rotate(int[] nums, int k) {
  k %= nums.length;
  reverse(nums, 0, nums.length - 1);
  reverse(nums, 0, k - 1);
  reverse(nums, k, nums.length - 1);
}

// reverse array from begin to end
private void reverse(int[] a, int begin, int end) {
  for (int temp; begin < end; begin++, end--) {
    temp = a[begin];
    a[begin] = a[end];
    a[end] = temp;
  }
}

54. Spiral Matrix
二維陣列螺旋形遍歷。

public List<Integer> spiralOrder(int[][] matrix) {
  List<Integer> result = new LinkedList<>();
  if (matrix.length == 0) return result;
  int m = matrix.length, n = matrix[0].length;
  for (int start = 0; m - 1 >= 2 * start && n - 1 >= 2 * start; start++) {
    int rowEnd = m - start - 1, colEnd = n - start - 1, i, j;
    for (j = start; j <= colEnd; j++) // left move
      result.add(matrix[start][j]);
    if (rowEnd == start) break;
    for (i = start + 1; i <= rowEnd; i++) // down move
      result.add(matrix[i][colEnd]);
    if (colEnd == start) break;
    for (j = colEnd - 1; j >= start; j--) // right move
      result.add(matrix[rowEnd][j]);
    for (i = rowEnd - 1; i > start; i--) // top move
      result.add(matrix[i][start]);
  }
  return result;
}

59. Spiral Matrix II
上一問題的變種,生成螺旋形二維陣列。

public int[][] generateMatrix(int n) {
  int[][] matrix = new int[n][n];
  for (int start = 0, cnt = 1; n - 1 >= 2 * start; start++) {
    int end = n - start - 1, i, j;
    for (j = start; j <= end; j++, cnt++) // left move
      matrix[start][j] = cnt;
    if (end == start) break;
    for (i = start + 1; i <= end; i++, cnt++) // down move
      matrix[i][end] = cnt;
    for (j = end - 1; j >= start; j--, cnt++) // right move
      matrix[end][j] = cnt;
    for (i = end - 1; i > start; i--, cnt++) // top move
      matrix[i][start] = cnt;
  }
  return matrix;
}

48. Rotate Image
順時針旋轉矩陣,相當於每一次把四個對應元素做旋轉。

  public void rotate(int[][] matrix) {
    int n = matrix.length;
    for (int i = 0; i < n / 2; i++) {
      for (int j = i; j < n - i - 1; j++) {
        int temp = matrix[i][j];
        matrix[i][j] = matrix[n - j - 1][i];
        matrix[n - j - 1][i] = matrix[n - i - 1][n - j - 1];
        matrix[n - i - 1][n - j - 1] = matrix[j][n - i - 1];
        matrix[j][n - i - 1] = temp;
      }
    }
  }

73. Set Matrix Zeroes
將有0元素的行與列全置為0;用兩個set儲存這樣的行列,然後再置為0——空間複雜度大概為\(O(m+n)\),並非為最優解。

public void setZeroes(int[][] matrix) {
  if (matrix.length == 0) return;
  int m = matrix.length, n = matrix[0].length;
  Set<Integer> rows = new HashSet<>(); // mark rows which contain 0
  Set<Integer> columns = new HashSet<>(); // mark columns which contain 0
  // phase 1: find zeroes
  for (int i = 0; i < m; i++) {
    for (int j = 0; j < n; j++) {
      if (matrix[i][j] == 0) {
        rows.add(i);
        columns.add(j);
      }
    }
  }
  // phase 2: set rows and columns
  for (Integer i : rows) {
    for (int j = 0; j < n; j++) {
      matrix[i][j] = 0;
    }
  }
  for (Integer j : columns) {
    for (int i = 0; i < m; i++) {
      matrix[i][j] = 0;
    }
  }
}

相關推薦

LeetCode題解陣列Array

1. 陣列 直觀地看,陣列(Array)為一個二元組<index, value>的集合——對於每一個index,都有一個value與之對應。C語言中,以“連續的儲存單元”實現陣列: int arr[5], *p_arr[5]; 陣列提供以\(O(1)\)的複雜度訪問元素,下標從0開始。但是,陣列的

LeetCode題解350_兩個陣列的交集Ⅱ

【LeetCode題解】350_兩個陣列的交集Ⅱ 文章目錄 【LeetCode題解】350_兩個陣列的交集Ⅱ 描述 方法一:對映 Java 實現 Python 實現 類似的 Python 實現

LeetCode題解349_兩個陣列的交集

【LeetCode題解】349_兩個陣列的交集 文章目錄 【LeetCode題解】349_兩個陣列的交集 描述 方法一:兩個雜湊表 Java 實現 類似的 Java 實現 Python 實現

LeetCode題解160_相交鏈表

結果 user 實現 ini tno href 假設 分享圖片 pytho 目錄 160_相交鏈表 描述 解法一:哈希表 思路 Java 實現 Python 實現 解法二:雙指針(推薦) 思路 Java 實現 Python 實現 160_相交鏈表 描述 編寫一個程

LeetCode題解142_環形連結串列2(Linked-List-Cycle-II)

目錄 描述 解法一:雜湊表 思路 Java 實現 Python 實現 複雜度分析 解法二:雙指標 思路 Java 實現 Python 實現 複雜度分析 描述 給定一個連結串列,返回連結串列開始入

LeetCode題解61_旋轉連結串列(Rotate-List)

目錄 描述 解法:雙指標 思路 Java 實現 Python 實現 複雜度分析 描述 給定一個連結串列,旋轉連結串列,將連結串列每個節點向右移動 k 個位置,其中 k 是非負數。 示例 1: 輸入: 1->2->3->4-

LeetCode題解61_旋轉鏈表(Rotate-List)

__init__ span leetcode 我們 分享 圖片 表示 執行 elf 目錄 描述 解法:雙指針 思路 Java 實現 Python 實現 復雜度分析 描述 給定一個鏈表,旋轉鏈表,將鏈表每個節點向右移動 k 個位置,其中 k 是非負數。 示例 1: 輸入

LeetCode題解347_前K個高頻元素(Top-K-Frequent-Elements)

目錄 描述 解法一:排序演算法(不滿足時間複雜度要求) Java 實現 Python 實現 複雜度分析 解法二:最小堆 思路 Java 實現 Python 實現 複雜度分析 解法三:桶排序(bucket s

LeetCode題解動態規劃:從新手到專家(一)

【LeetCode題解】動態規劃:從新手到專家(一) 文章標題借用了Hawstein的譯文《動態規劃:從新手到專家》。 1. 概述 動態規劃( Dynamic Programming, DP)是最優化問題的一種解決方法,本質上狀態空間的狀態轉移。所謂狀態轉移是指每個階段的最優狀態(對應於

LeetCode題解二叉樹的遍歷

【LeetCode題解】二叉樹的遍歷 我準備開始一個新系列【LeetCode題解】,用來記錄刷題,順便複習一下資料結構與演算法。 1. 二叉樹 二叉樹(binary tree)是一種極為普遍的資料結構,樹的每一個節點最多隻有兩個節點——左孩子結點與右孩子結點。C實現的二叉樹: str

LeetCode題解24_兩兩交換連結串列中的節點(Swap-Nodes-in-Pairs)

目錄 描述 解法一:迭代 思路 Java 實現 Python 實現 複雜度分析 解法二:遞迴(不滿足空間複雜度要求) 思路 Java 實現 Python 實現 複雜度分析 更多 LeetCo

LeetCode題解19_刪除連結串列的倒數第N個節點(Remove-Nth-Node-From-End-of-List)

更多 LeetCode 題解筆記可以訪問我的 github。 文章目錄 描述 解法:雙指標 思路 Java 實現 Python 實現 複雜度分析 描述 給定一個連結串列,

LeetCode題解231_2的冪(Power-of-Two)

文章目錄 描述 解法 1:判斷整數 $x$ 的二進位制表示中是否只有一位為1 實現方式 1:除以 2 Java 實現(非遞迴) Python 實現(非遞迴) Java 實現(遞迴) Python

LeetCode題解9_迴文數(Palindrome-Number)

9_迴文數(Palindrome-Number) 文章目錄 9_迴文數(Palindrome-Number) 描述 解法一:轉化為字串的比較 思路 Java 實現 Python 實現 複雜

LeetCode題解20_有效的括號(Valid-Parentheses)

20_有效的括號(Valid-Parentheses) 文章目錄 20_有效的括號(Valid-Parentheses) 描述 解法 思路 Java 實現 Python 實現 複雜度分析

LeetCode題解206_反轉連結串列(Reverse-Linked-List)

更多 LeetCode 題解筆記可以訪問我的 github。 文章目錄 描述 解法一:迭代 思路 Java 實現 Python 實現 複雜度分析 解法二:遞迴 思路

LeetCode題解7_反轉整數

【LeetCode題解】7_反轉整數 文章目錄 【LeetCode題解】7_反轉整數 描述 方法一 思路 Java 實現 類似的 Java 實現 Python 實現 方法

LeetCode題解94_二叉樹的中序遍歷

【LeetCode題解】94_二叉樹的中序遍歷 文章目錄 【LeetCode題解】94_二叉樹的中序遍歷 描述 方法一:遞迴 Java 程式碼 Python程式碼 方法二:非遞迴

LeetCode題解21_合併兩個有序連結串列

21_合併兩個有序連結串列 文章目錄 21_合併兩個有序連結串列 描述 解法一:迭代 思路 Java 實現 Python 實現 解法二:遞迴 思路 J

LeetCode題解237_刪除連結串列中的節點

237_刪除連結串列中的節點 文章目錄 237_刪除連結串列中的節點 描述 解法 思路 Java 實現 Python 實現 描述 請編寫一個函式,使其可以刪除