LeetCode之資料結構——陣列

雪心玉竹發表於2018-08-21

data structure picture

從今天開始刷LeetCode,目標:每週至少刷一個Coding Question,出一篇data structure學習博文進行總結。Fighting!
解出的程式碼案例也都會在我的GitHub上進行維護。如果覺得對您有幫助,歡迎star or fork~
附上GitHub專案地址:https://github.com/zrxJuly/dataStructure
Blog:zrxJuly’s Blog,歡迎訪問,Let’s study together.

陣列簡介

  陣列是資料結構中的基本模組之一,因為字串是由字元陣列形成的,所以二者是相似的。
陣列是一種基本的資料結構,用於按順序儲存元素集合,陣列中的每個元素都可以通過陣列索引來識別,元素可以隨機存取。陣列可以有一個或多個維度,
   一維陣列:也叫線性陣列。陣列具有固定的容量,我們需要在初始化時指定陣列的大小。然而這種在初始化時指定陣列大小的方法會很不方便甚至可能會造成浪費。

Array Demo學習

package com.zrxjuly.ds.arrayandstring.study;

import java.util.Arrays;
/**
 * @Description 陣列的基本用法.
 */
public class Array {
    public static void arrayTest() {
        // 1. Initialize.初始化陣列.
        int[] a0 = new int[5];
        int[] a1 = { 1, 2, 3 };
        // 2. Get Length.輸出陣列長度.
        System.out.println("The size of a1 is: " + a1.length);
        // 3. Access Element.訪問陣列元素.
        System.out.println("The first element is: " + a1[0]);
        // 4. Iterate all Elements.遍歷所有元素,兩個for迴圈,兩種遍歷方法.
        System.out.print("[Version 1] The contents of a1 are:");
        for (int i = 0; i < a1.length; ++i) {
            System.out.print(" " + a1[i]);
        }
        System.out.println();
        System.out.print("[Version 2] The contents of a1 are:");
        for (int item : a1) {
            System.out.print(" " + item);
        }
        System.out.println();
        // 5. Modify Element.修改指定下標的陣列元素.
        a1[0] = 4;
        // 6. Sort.對陣列進行排序.
        Arrays.sort(a1);
    }

    public static void main(String[] args) {
        arrayTest();
    }
}

動態陣列簡介

動態陣列:是大小可變的隨機存取的列表資料結構。大多數程式語言都會提供內建的動態陣列。eg:在C++中的vector,Java中的ArrayList。

Dynamic Array Demo 學習

package com.zrxjuly.ds.arrayandstring.study;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
 * @Description 動態陣列
 *   大小可變的隨機存取的列表資料結構.
 */
public class DynamicArray {
    public static void dynamicArray() {
        // 1. 集合初始化.
        List<Integer> v0 = new ArrayList<>();
        List<Integer> v1;
        // 宣告並賦值陣列.
        Integer[] a = {0, 1, 2, 3, 4};
        // Arrays.asList()方法:將陣列轉化為List,該方法將陣列與列表連結起來,當更新其中一個時,另一個也會更新.
        v1 = new ArrayList<>(Arrays.asList(a));
        // 3. 將v1陣列賦值給v2
        List<Integer> v2 = v1;                      // another reference to v1
        List<Integer> v3 = new ArrayList<>(v1);     // make an actual copy of v1
        // 3. get length
        System.out.println("The size of v1 is: " + v1.size());;
        // 4. access element
        System.out.println("The first element in v1 is: " + v1.get(0));
        // 5. iterate the vector.下面兩種方法遍歷集合內容.
        System.out.print("[Version 1] The contents of v1 are:");
        for (int i = 0; i < v1.size(); i ++) {
            System.out.print(" " + v1.get(i));
        }
        System.out.println();
        System.out.print("[Version 2] The contents of v1 are:");
        for (int item : v1) {
            System.out.print(" " + item);
        }
        
        System.out.println();
        // 6. modify element.修改元素,注意:v1使用Arrays.asList()方法賦值,因此v2中的元素修改後,v1也會修改
        v2.set(0, 5);       // modify v2 will actually modify v1
        System.out.println("The first element in v1 is: " + v1.get(0));
        v3.set(0, -1);
        System.out.println("The first element in v1 is: " + v1.get(0));
        // 7. sort. 對集合進行排序
        Collections.sort(v1);
        // 8. add new element at the end of the vector
        v1.add(-1);
        System.out.print("[Version 2] The contents of v1 are:");
        for (int item : v1) {
            System.out.print(" " + item);
        }
        System.out.println();
        v1.add(1, 6);
        System.out.print("[Version 2] The contents of v1 are:");
        for (int item : v1) {
            System.out.print(" " + item);
        }
        System.out.println();
        // 9. delete the last element
        v1.remove(v1.size() - 1);
        System.out.print("[Version 2] The contents of v1 are:");
        for (int item : v1) {
            System.out.print(" " + item);
        }
    }
    
    public static void main(String[] args) {
        dynamicArray();
    }
}

Coding Question:尋找陣列的中心索引

該Coding Question是LeetCode上陣列模組的第一個程式設計問題。這裡展示了兩種解題思路及方法:
思路一
目標索引的左側的數的總和 = 目標索引的右側的數的總和。
思路二
左側及索引對應的數 的總和+索引對應的數 = 總和-左側及索引對應的數的總和+索引對應的數。

詳細分析請看程式碼及註釋,或訪問:https://github.com/zrxJuly/dataStructure

package com.zrxjuly.ds.arrayandstring.demo;

/**
 * 
 * @author: zrxJuly
 * @Date: 2018-8-21 17:00:55
 * @Desription: Find Pivot Index. 尋找陣列的中心索引。
 *   Coding Question:
 *       Given an array of integers nums, write a method that returns the "pivot" index of this array.
 *       We define the pivot index as the index where the sum of the numbers to the left of the index 
 *       is equal to the sum of the numbers to the right of the index.
 *       If no such index exists, we should return -1. 
 *       If there are multiple pivot indexes, you should return the left-most pivot index.
 *   |-題目:尋找陣列的中心索引。
 *       給定一個整數型別的陣列,編寫一個返回陣列中心索引的方法。
 *       陣列中心索引的定義:索引左側的數的總和 = 索引右側的數的總和。
 *       如果不存在這樣的索引,返回-1.
 *       如果存在多箇中心索引,應該返回最左側的中心索引。
 * 
 */
public class FindPivotIndex {
    /**
     * Solution 1.
     * |-思路分析:目標索引的左側的數的總和 = 目標索引的右側的數的總和.
     *     陣列:[1, 7, 3, 6, 5, 6 ]
     *           |______|  | |___|
     *              |      |   |
     *              A      B   C 
     *     假設 A:目標索引左側的總和,C:目標索引右側總和,B:目標索引對應的數值.
     *     則 若有:A = C, 符合題意,返回B的索引,否則返回-1.
     * |- 分別宣告左側總和numsLeft 以及 右側總和numsRight 兩個變數,for迴圈分別遍歷兩側元素,最後比較是否相等.
     * @param nums
     * @return
     */
    public static int pivotIndexSolution1(int[] nums) {
        for (int i = 0; i < nums.length; i++) {
            // 宣告左側變數.
            int numsLeft = 0;
            // 宣告右側變數.
            int numsRight = 0;
            // 遍歷i左側元素,值相加.
            for (int m = 0; m < i; m++) {
                numsLeft += nums[m];
            }
            // 遍歷i右側元素,值相加.
            for (int n = nums.length - 1; n > i; n--) {
                numsRight += nums[n];
            }
            // 若左側值和右側值相等,返回i值.
            if (numsLeft == numsRight) {
                return i;
            }
        }

        return -1;
    }
    
    /**
     * Solution 2.
     * |-思路分析:左側及索引對應的數 的總和+索引對應的數 = 總和-左側及索引對應的數的總和+索引對應的數.
     *   |-下面這樣解釋更容易理解:
     *     陣列:[1, 7, 3, 6, 5, 6 ]
     *           |______|  | |___|
     *              |      |   |
     *              A      B   C 
     *     假設 A:目標索引左側的總和,C:目標索引右側總和,B:目標索引對應的數值.
     *     則 若有:A + B = B + C,即 A = C, 符合題意,返回B的索引,否則返回-1.
     *     
     *   |-下面程式碼中是這樣判斷的:
     *     分別宣告兩個變數:陣列總和sum 以及 陣列左側總和 lsum
     *     先用for迴圈遍歷得出陣列總和sum,然後再寫一個for迴圈,在該迴圈內判斷左側總和lsum是否和右側總和相等。
     *     (注:本例中lsum包含了目標索引的值,因此在判斷的時候右側總和也必須加上目標索引的值)
     *     
     * @param nums
     * @return
     */
    public static int pivotIndexSolution2(int[] nums) {
        int len = nums.length;
        // 陣列總和.
        int sum = 0;
        // 陣列左側數的總和.
        int lsum = 0;
        // 得出陣列總和.
        for(int x:nums){
            sum+=x;
        }
        
        for(int i = 0;i<len;i++){
            lsum += nums[i];
            // 判斷:左側總和 == 右側總和
            if(lsum == sum - lsum + nums[i]){
                return i;
            }
        }
        
        return -1;
    }
    
    public static void main(String[] args) {
        // Initialize.初始化陣列.
        int[] nums = {1, 7, 3, 6, 5, 6};
//        int[] nums = {-1,-1,-1,0,1,1};
        // 呼叫方法一:
        int result1 = pivotIndexSolution1(nums);
        System.out.println("The first method result is:" + result1);
        // 呼叫方法二:
        int result2 = pivotIndexSolution2(nums);
        System.out.println("The second method result is:" + result2);
    }
}

相關文章