---
# System prepended metadata

title: LeetCode 刷起來

---

# LeetCode 刷起來

###### tags: `LeetCode`

## Two Sum (難度：Easy)

https://leetcode.com/problems/two-sum/

```php
class Solution {

    /**
     * @param Integer[] $nums
     * @param Integer $target
     * @return Integer[]
     */
    function twoSum($nums, $target) {
        $tmp = [];
        foreach ($nums as $inedx => $num) {
            if (array_key_exists($target - $num, $tmp)) {
                return [$tmp[$target - $num], $inedx];
            }

            $tmp[$num] = $inedx;
        }

        return null;
    }
}

```

## Two Sum II - Input Array Is Sorted(難度：Medium)
https://leetcode.com/problems/two-sum-ii-input-array-is-sorted/
### GO
```go
func twoSum(numbers []int, target int) []int {
    left := 0;
    right := len(numbers) - 1
    for right > left {
        sum := numbers[left] + numbers[right]
        if sum == target {
            return []int{left+1, right+1}
        } else if target > sum  {
           left++
        } else {
            right--
        }
    }

    return []int{}
}
```

### PHP
```php
class Solution {

    /**
     * @param Integer[] $numbers
     * @param Integer $target
     * @return Integer[]
     */
    function twoSum($numbers, $target) {
        $left = 0;
        $right = count($numbers) - 1;
        while ($right > $left) {
            $sum = $numbers[$right] + $numbers[$left];
            if ($sum === $target) {
                return [$left + 1, $right + 1];
            } else if ($sum > $target) {
                $right--;
            } else {
                $left++;
            }
        }

        return [];
    }
}
```


## Merge Two Sorted Lists (難度：Easy)

https://leetcode.com/problems/merge-two-sorted-lists/

```php
/**
 * Definition for a singly-linked list.
 * class ListNode {
 *     public $val = 0;
 *     public $next = null;
 *     function __construct($val = 0, $next = null) {
 *         $this->val = $val;
 *         $this->next = $next;
 *     }
 * }
 */
class Solution {

    /**
     * @param ListNode $list1
     * @param ListNode $list2
     * @return ListNode
     */
    function mergeTwoLists($list1, $list2) {
        if (empty($list1)) {
            return $list2;
        }

        if (empty($list2)) {
            return $list1;
        }

        $mergeList = new ListNode();

        if ($list1->val >= $list2->val){
            $mergeList->val = $list2->val;
            $mergeList->next = $this->mergeTwoLists($list1, $list2->next);
        } else {
            $mergeList->val = $list1->val;
            $mergeList->next = $this->mergeTwoLists($list1->next, $list2);
        }

        return $mergeList;
    }
}

```

## Binary Search (難度：Easy)

https://leetcode.com/problems/binary-search/

```php
class Solution {

    /**
     * @param Integer[] $nums
     * @param Integer $target
     * @return Integer
     */
    function search($nums, $target) {
        $min = 0;
        $max = count($nums) - 1;

        $index = -1;
        while ($min <= $max) {
            $mid = floor(($max + $min) / 2);

            if ($nums[$mid] === $target) {
                $index = $mid;
                break; 
            }

            if ($nums[$mid] > $target) {
                $max = $mid - 1;
            } else if ($nums[$mid] < $target) {
                $min = $mid + 1;
            }
        }

        return $index;
    }
}
```


## Remove Duplicates from Sorted Array(難度：Easy)
https://leetcode.com/problems/remove-duplicates-from-sorted-array/

### GO
```go
func removeDuplicates(nums []int) int {
    if len(nums) == 0 {
        return 0
    }

    k := 1
    for i := 1; i < len(nums); i++ {
        if (nums[i] != nums[i-1]) {
            nums[k] = nums[i]
            k++
        }
    }

    return k
}

```

### PHP
```php
class Solution {

    /**
     * @param Integer[] $nums
     * @return Integer
     */
    function removeDuplicates(&$nums) {
        $nums = array_unique($nums);
        return count($nums);
    }
}
```

## Remove Duplicates from Sorted Array II(難度：Medium)
https://leetcode.com/problems/remove-duplicates-from-sorted-array-ii

### GO
```go
func removeDuplicates(nums []int) int {
    if len(nums) == 0 {
        return 0
    }

    k := 1
    duplicates := 0
    for i := 1; i < len(nums); i++ {
        if nums[i] != nums[i-1] {
            nums[k] = nums[i]
            duplicates = 0
            k++
        } else {
            duplicates++
            if duplicates < 2 {
                nums[k] = nums[i]
                k++
            }
        }
    }

    return k
}
```

### PHP
```php
class Solution {

    /**
     * @param Integer[] $nums
     * @return Integer
     */
    function removeDuplicates(&$nums) {
        if (count($nums) === 0) {
            return 0;
        }

        $k = 1;
        $duplicates = 0;
        for ($i = 1; $i < count($nums); $i++) {
            if ($nums[$i] !== $nums[$i -1]) {
                $nums[$k] = $nums[$i];
                $duplicates = 0;
                $k++;
            } else {
                $duplicates++;
                if ($duplicates < 2) {
                    $nums[$k] = $nums[$i];
                    $k++;
                }
            }
        }

        return $k;
    }
}
```


## Minimum Size Subarray Sum(難度：Medium)
https://leetcode.com/problems/minimum-size-subarray-sum/

- 經典 Sliding Window，右邊界(`right`)依序往右走並累加 `sum`，當 `sum` 大於 `target` 時，紀錄 window size。
- 接著左邊界(`left`)開始移動，window size 縮小，直到 `sum` 小於 `target`，找到前段最小 window size。
- 然後 window 開始向右開始移動(左右邊界開始右移)，期間如果有 `sum` 小於 `target`，重複上一步驟縮小 window size，縮小後 window 再開始右移，直到陣列最後。

### GO
```go
func minSubArrayLen(target int, nums []int) int {
    left, sum := 0, 0
    minSize := len(nums) + 1
    for right := 0; right < len(nums); right++ {
        sum += nums[right]
        for sum >= target {
            if minSize > right - left + 1 {
                minSize = right - left + 1
            }
            sum -= nums[left]
            left++
        }
    }

    if minSize > len(nums) {
        return 0
    }

    return minSize
}
```

### PHP
```php
class Solution {

    /**
     * @param Integer $target
     * @param Integer[] $nums
     * @return Integer
     */
    function minSubArrayLen($target, $nums) {
        $left = 0;
        $sum = 0;
        $minSize = count($nums) + 1;

        foreach ($nums as $right => $value) {
            $sum += $value;
            while ($sum >= $target) {
                if ($minSize > $right - $left + 1) {
                    $minSize = $right - $left + 1;
                }
                $sum -= $nums[$left];
                $left++;
            }
        }
        
        if ($minSize > count($nums)) {
            return 0;
        }

        return $minSize;
    }
}
```

## Minimum Window Substring(難度：Hard)
https://leetcode.com/problems/minimum-window-substring/

- 字串 `s` 中，先固定 `left`，`right` 移動至包含所有字串 `t` 的字母，並記下當時的 `left` 跟 window size。
- 接著 `left` 開始移動，直到遇見字串 `t` 中的任一字母，並記下當時的 `left` 跟 window size。
- `left` 右移一格後，這時代表代表包含所有字串 `t` 的字母少一個，因此 `right` 一格一格往右移，直到遇見上一步的字母。
- `right` 遇見字母後，重複步驟二，換 `left` 移動，直到 `right` 移到字串 `s` 最後一個字母 
- 範例 s = `"ADOBANCKSS"`, t = `"ABC"` :
```
// 第 1 次: A => right 開始移動
// 第 2 次: AD
// 第 3 次: ADO
// 第 4 次: ADOB
// 第 5 次: ADOBA
// 第 6 次: ADOBAN
// 第 7 次: ADOBANC => 符合條件，已包含所有字串 `t` 的字母
// 第 8 次: DOBANC => 換 left 開始移動
// 第 9 次: OBANC
// 第 10 次: BANC => 遇到字串 `t` 包含的字母(B)，下一步要保持 window size，left & right 向右移一格
// 第 11 次: ANCK => left 向右移少了字母 B，left 固定，right 要向右找到新的字母 B
// 第 12 次: ANCKS 
// 第 13 次: ANCKSS => right 走到最後了，未遇到新的字母 B，min window 是 BANC
```

```go
func minWindow(s string, t string) string {
	if len(t) > len(s) {
		return ""
	}

	letters := make(map[string]int)
	for i := 0; i < len(t); i++ {
		letters[string(t[i])]++
	}

	minWindowLeft := 0
	minWindowSize := len(s) + 1
	left, right := 0, 0

	counter := len(t)
	for right < len(s) {
		if letters[string(s[right])] > 0 {
			counter--
		}
		letters[string(s[right])]--
		right++

		for counter == 0 {
			if minWindowSize > right-left {
				minWindowLeft = left
				minWindowSize = right - left
			}

			letters[string(s[left])]++
			if letters[string(s[left])] == 1 {
				counter++
			}

			left++
		}
	}

	if minWindowSize > len(s) {
	    return ""
	}

	return s[minWindowLeft:minWindowLeft+minWindowSize]
}
```

## Maximum Depth of Binary Tree(難度：Easy)
https://leetcode.com/problems/maximum-depth-of-binary-tree/
左右 node 一層層統計下去，各層累加後取最大的 depth

```go
/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func maxDepth(root *TreeNode) int {
    if (root == nil) {
        return 0
    }

    return 1 + max(maxDepth(root.Left), maxDepth(root.Right))
}
```

## Construct Binary Tree from Preorder and Inorder Traversal(難度：Medium)
https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/

- `pre-order` 是從 `root` 開始，然後總是從 left node 開始遍歷。如果依 root 分左右元樹，遍歷結果有個規律：`root, {左元樹所有 node...}, {左元樹所有 node...}`，如範例 `3,9,20,15,7`，3 是 `root`，接著 9 屬於左元樹 node，再來的 20、15、7 屬於右元樹 node。
- `in-order` 是從 `root` 切分，左元樹最底層且最左邊的 node 開始，然後依 left -> parent -> right 順序遍歷，遍歷結果有個規律：`{左元樹所有 node...}, root, {左元樹所有 node...}`，如範例 `9,3,15,20,7`，9 屬於左元樹 node，接著 3 是 `root`，再來 20、15、7 屬於右元樹 node。
- 綜上，`preorder` 的第一個數值就是 `root`，找到 `root` 值在 `inorder` 陣列的 index 位置，idex 前面的數值都在左元樹，後面的數值都在右元樹。利用這規律，用遞迴方式，從最上層、第二層、第三層...慢慢建構出 binary tree。

```go
/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func buildTree(preorder []int, inorder []int) *TreeNode {
	if len(inorder) == 0 {
		return nil
	}

	root := preorder[0]
	i := slices.Index(inorder, root)

	leftPreorder := preorder[1:i+1]
	leftInorder := inorder[:i]

	rightPreorder := preorder[i+1:]
	rightInorder := inorder[i+1:]

	return &TreeNode{
	    Val: preorder[0],
	    Left: buildTree(leftPreorder, leftInorder),
	    Right: buildTree(rightPreorder, rightInorder),
	}
}
```

## Binary Tree Right Side View(難度：Medium)
https://leetcode.com/problems/binary-tree-right-side-view/

- 注意一些例子 root:`[1,2,3,null,5,null,null]` => ouput: `[1,3,5]` & root:`[1,2,3,6,null,null,null]` => ouput: `[1,3,6]`，右元樹最底層沒有數值時，要補上左元樹該層最右邊的值，binary tree 深度會等於回傳陣列的長度，所以先查右元樹後要再查左元樹。

```go
/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func rightSideView(root *TreeNode) []int {
    result := []int{}
    appendNodeVal(root, 1, &result)
    return result
}

func appendNodeVal(node *TreeNode, depth int, result *[]int) {
    if node == nil {
        return
    }

    if depth > len(*result) {
        *result = append(*result, node.Val)
    }

    appendNodeVal(node.Right, depth+1, result)
    appendNodeVal(node.Left, depth+1, result)
}
```

## Validate Binary Search Tree(難度：Medium)
https://leetcode.com/problems/validate-binary-search-tree/

node `Val` 必須在最大最小值範圍裡，檢查左子層限定 max，檢查右子層限定 min，最上層初始 mix & max 設定介於題目限定的 `-2^31 ~ 2^31-1`


```GO
/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func isValidBST(root *TreeNode) bool {
    return isValid(root, math.MinInt, math.MaxInt)
}

func isValid(node *TreeNode, min, max int) bool {
    if node == nil {
        return true
    }

    if node.Val <= min || node.Val >= max {
        return false
    }

    return isValid(node.Left, min, node.Val) && isValid(node.Right, node.Val, max) 
}

```

## Find Peak Element(難度：Medium)
https://leetcode.com/problems/find-peak-element/

經典 Binary Search，target 改成 `mid` 對應的值即可

```go
func findPeakElement(nums []int) int {
    left := 0
    right := len(nums) - 1
    for right > left {
        mid := (left + right) / 2
        if nums[mid] > nums[mid+1] {
            right = mid
        } else {
            left = mid + 1
        }
    }

    return left
}
```

## Find First and Last Position of Element in Sorted Array(難度：Medium)
https://leetcode.com/problems/find-first-and-last-position-of-element-in-sorted-array/

兩次 Binary Search，先找出 `start`(`left`)，再找出 `end`(`right`)

```go
func searchRange(nums []int, target int) []int {
    if len(nums) == 0 {
        return []int{-1, -1}
    }

    start := searchStart(nums, target)
    if start == -1 {
       return []int{-1, -1} 
    }

    end := searchEnd(nums, target, start)
    return []int{start, end}
}

func searchStart(nums []int, target int) int {
    left := 0
    right := len(nums) - 1
    for right > left {
        mid :=  (left + right) / 2

        if nums[mid] >= target {
            right = mid
        } else {
            left = mid + 1
        }
    }

    if (nums[left] == target) {
        return left
    }

    return -1
}

func searchEnd(nums []int, target int, left int) int {
    right := len(nums) - 1
    for right > left {
        mid :=  (left + right) / 2

        if nums[mid] > target {
            right = mid
        } else {
            left = mid + 1
        }
    }

    if (nums[right] == target) {
        return right
    }

    if (nums[right - 1] == target) {
        return right - 1
    }

    return -1
}
```

