Leetcode數據結構與算法(五)

[0065]漢明距離

兩個整數之間的漢明距離指的是這兩個數字對應二進制位不同的位置的數目。

給出兩個整數 x 和 y,計算它們之間的漢明距離。

注意:

0 ≤ x, y < 231.

示例:

輸入: x = 1, y = 4

輸出: 2

解釋:
1   (0 0 0 1)
4   (0 1 0 0)
       ↑   ↑

上面的箭頭指出了對應二進制位不同的位置。

方法一:異或

class Solution {
    public int hammingDistance(int x, int y) {
        return countBitNumber(x^y);
    }
    //1.兩個數字異或之後可以得到 不同二進制位的數字
    //2.計算該數字中1的個數,即是漢明距離
    //計算1的個數時,有幾種方法,1:不斷和左移的1 進行 與,判斷該位是否爲1.
    //                       2: n&(n-1)就是把n最右邊的bit 1 位去掉,看能去掉幾次,就有幾個1位。(布賴恩·克尼根算法)
    int countBitNumber(int n)
    {
        int count = 0;
        while(n != 0)			
        {
            n = (n & n-1);
            ++count;
        }
				//while (n != 0) {
        //    if (n % 2 == 1)
        //       count += 1;
        //    n = n >> 1;
        //}
        return count;
    }
}

方法二:內置

class Solution {
    public int hammingDistance(int x, int y) {
        return Integer.bitCount(x ^ y); 
    }
}

[0066]將有序數組轉換爲二叉搜索樹

將一個按照升序排列的有序數組,轉換爲一棵高度平衡二叉搜索樹。

本題中,一個高度平衡二叉樹是指一個二叉樹每個節點 的左右兩個子樹的高度差的絕對值不超過 1。

示例:

給定有序數組: [-10,-3,0,5,9],

一個可能的答案是:[0,-3,9,-10,null,5],它可以表示下面這個高度平衡二叉搜索樹:

      0
     / \
   -3   9
   /   /
 -10  5

https://leetcode-cn.com/problems/convert-sorted-array-to-binary-search-tree/solution/jiang-you-xu-shu-zu-zhuan-huan-wei-er-cha-sou-s-15/

方法一:

class Solution {
  int[] nums;

  public TreeNode helper(int left, int right) {
    if (left > right) return null;

    // always choose left middle node as a root
    int p = (left + right) / 2;

    // inorder traversal: left -> node -> right
    TreeNode root = new TreeNode(nums[p]);
    root.left = helper(left, p - 1);
    root.right = helper(p + 1, right);
    return root;
  }

  public TreeNode sortedArrayToBST(int[] nums) {
    this.nums = nums;
    return helper(0, nums.length - 1);
  }
}

[0067]反轉字符串中的單詞 III

給定一個字符串,你需要反轉字符串中每個單詞的字符順序,同時仍保留空格和單詞的初始順序。

示例 1:

輸入: "Let's take LeetCode contest"
輸出: "s'teL ekat edoCteeL tsetnoc" 

注意:在字符串中,每個單詞由單個空格分隔,並且字符串中不會有任何額外的空格。

方法一:

class Solution {
    public String reverseWords(String s) {
        String words[] = s.split(" ");
        StringBuilder res=new StringBuilder();
        for (String word: words)
            res.append(new StringBuffer(word).reverse().toString() + " ");
        return res.toString().trim();    
    }
}

方法二:

public class Solution {
    public String reverseWords(String s) {
        String words[] = split(s);
        StringBuilder res=new StringBuilder();
        for (String word: words)
            res.append(reverse(word) + " ");
        return res.toString().trim();
    }
    public String[] split(String s) {
        ArrayList < String > words = new ArrayList < > ();
        StringBuilder word = new StringBuilder();
        for (int i = 0; i < s.length(); i++) {
            if (s.charAt(i) == ' ') {
                words.add(word.toString());
                word = new StringBuilder();
            } else
                word.append( s.charAt(i));
        }
        words.add(word.toString());
        return words.toArray(new String[words.size()]);
    }
    public String reverse(String s) {
      StringBuilder res=new StringBuilder();
        for (int i = 0; i < s.length(); i++)
            res.insert(0,s.charAt(i));
        return res.toString();
    }
}

方法三:

public class Solution {
    public String reverseWords(String input) {
        final StringBuilder result = new StringBuilder();
        final StringBuilder word = new StringBuilder();
        for (int i = 0; i < input.length(); i++) {
            if (input.charAt(i) != ' ') {
                word.append(input.charAt(i));
            } else {
                result.append(word.reverse());
                result.append(" ");
                word.setLength(0);
            }
        }
        result.append(word.reverse());
        return result.toString();
    }
}

[0068]非遞增順序的最小子序列

給你一個數組 nums,請你從中抽取一個子序列,滿足該子序列的元素之和 嚴格 大於未包含在該子序列中的各元素之和。

如果存在多個解決方案,只需返回 長度最小 的子序列。如果仍然有多個解決方案,則返回 元素之和最大 的子序列。

與子數組不同的地方在於,「數組的子序列」不強調元素在原數組中的連續性,也就是說,它可以通過從數組中分離一些(也可能不分離)元素得到。

注意,題目數據保證滿足所有約束條件的解決方案是 唯一 的。同時,返回的答案應當按 非遞增順序 排列。

示例 1:

輸入:nums = [4,3,10,9,8]
輸出:[10,9] 
解釋:子序列 [10,9] 和 [10,8] 是最小的、滿足元素之和大於其他各元素之和的子序列。但是 [10,9] 的元素之和最大。 

示例 2:

輸入:nums = [4,4,7,6,7]
輸出:[7,7,6] 
解釋:子序列 [7,7] 的和爲 14 ,不嚴格大於剩下的其他元素之和(14 = 4 + 4 + 6)。因此,[7,6,7] 是滿足題意的最小子序列。注意,元素按非遞增順序返回。  

示例 3:

輸入:nums = [6]
輸出:[6]

方法一:

先排序下,倒序遍歷當前和是否大於剩餘和,並去符合條件的元素

class Solution {
       public List<Integer> minSubsequence(int[] nums) {
       List<Integer> res = new ArrayList<>();
       Arrays.sort(nums);
       int left = 0, sum = 0;
       for(int i : nums)
           left += i;
       for(int i = nums.length - 1; i >= 0; i--){
           sum += nums[i];
           left -= nums[i];
           res.add(nums[i]);
           if(sum > left)
               break;
       }
       return res;
   }
}

[0069]山脈數組的峯頂索引

我們把符合下列屬性的數組 A 稱作山脈:

  • A.length >= 3
  • 存在 0 < i < A.length - 1 使得A[0] < A[1] < … A[i-1] < A[i] > A[i+1] > … > A[A.length - 1]

給定一個確定爲山脈的數組,返回任何滿足 A[0] < A[1] < … A[i-1] < A[i] > A[i+1] > … > A[A.length - 1] 的 i 的值。

示例 1:

輸入:[0,1,0]
輸出:1

示例 2:

輸入:[0,2,1,0]
輸出:1

提示:

3 <= A.length <= 10000
0 <= A[i] <= 10^6
A 是如上定義的山脈

方法一:

class Solution {
    public int peakIndexInMountainArray(int[] A) {
        int i = 0;
        while (A[i] < A[i+1]) i++;
        return i;
    }
}

方法二:二分查找

class Solution {
    public int peakIndexInMountainArray(int[] A) {
        int lo = 0, hi = A.length - 1;
        while (lo < hi) {
            int mi = lo + (hi - lo) / 2;
            if (A[mi] < A[mi + 1])
                lo = mi + 1;
            else
                hi = mi;
        }
        return lo;
    }
}

[0070]反轉字符串

編寫一個函數,其作用是將輸入的字符串反轉過來。輸入字符串以字符數組 char[] 的形式給出。

不要給另外的數組分配額外的空間,你必須原地修改輸入數組、使用 O(1) 的額外空間解決這一問題。

你可以假設數組中的所有字符都是 ASCII 碼錶中的可打印字符。

示例 1:

輸入:["h","e","l","l","o"]
輸出:["o","l","l","e","h"]

示例 2:

輸入:["H","a","n","n","a","h"]
輸出:["h","a","n","n","a","H"]

方法一:雙指針法

class Solution {
    public void reverseString(char[] s) {
        int left = 0, right = s.length - 1;
        while (left < right) {
            char tmp = s[left];
            s[left++] = s[right];
            s[right--] = tmp;
        }
    }
}

方法二:

class Solution {
    public void reverseString(char[] s) {
        for(int i = 0; i < s.length / 2; i++){
            char tmp = s[i];
            s[i] = s[s.length - 1 - i];
            s[s.length - 1 - i] = tmp;
        }
    }
}

[0071]Nim 遊戲

你和你的朋友,兩個人一起玩 Nim 遊戲:桌子上有一堆石頭,每次你們輪流拿掉 1 - 3 塊石頭。 拿掉最後一塊石頭的人就是獲勝者。你作爲先手。

你們是聰明人,每一步都是最優解。 編寫一個函數,來判斷你是否可以在給定石頭數量的情況下贏得遊戲。

示例:

輸入: 4
輸出: false 
解釋: 如果堆中有 4 塊石頭,那麼你永遠不會贏得比賽;
     因爲無論你拿走 1 塊、2 塊 還是 3 塊石頭,最後一塊石頭總是會被你的朋友拿走。

方法:

class Solution {
    public boolean canWinNim(int n) {
         return (n % 4 != 0);
    }
}

[0072]可以被一步捕獲的棋子數

在一個 8 x 8 的棋盤上,有一個白色的車(Rook),用字符 ‘R’ 表示。棋盤上還可能存在空方塊,白色的象(Bishop)以及黑色的卒(pawn),分別用字符 ‘.’,‘B’ 和 ‘p’ 表示。不難看出,大寫字符表示的是白棋,小寫字符表示的是黑棋。

車按國際象棋中的規則移動。東,西,南,北四個基本方向任選其一,然後一直向選定的方向移動,直到滿足下列四個條件之一:

棋手選擇主動停下來。
棋子因到達棋盤的邊緣而停下。
棋子移動到某一方格來捕獲位於該方格上敵方(黑色)的卒,停在該方格內。
車不能進入/越過已經放有其他友方棋子(白色的象)的方格,停在友方棋子前。
你現在可以控制車移動一次,請你統計有多少敵方的卒處於你的捕獲範圍內(即,可以被一步捕獲的棋子數)。

示例 1:

輸入:[[".",".",".",".",".",".",".","."],
[".",".",".","p",".",".",".","."],
[".",".",".","R",".",".",".","p"],
[".",".",".",".",".",".",".","."],
[".",".",".",".",".",".",".","."],
[".",".",".","p",".",".",".","."],
[".",".",".",".",".",".",".","."],
[".",".",".",".",".",".",".","."]]
輸出:3
解釋:
在本例中,車能夠捕獲所有的卒。

示例 2:

輸入:[[".",".",".",".",".",".",".","."],
[".","p","p","p","p","p",".","."],
[".","p","p","B","p","p",".","."],
[".","p","B","R","B","p",".","."],
[".","p","p","B","p","p",".","."],
[".","p","p","p","p","p",".","."],
[".",".",".",".",".",".",".","."],
[".",".",".",".",".",".",".","."]]
輸出:0
解釋:
象阻止了車捕獲任何卒。

示例 3:

輸入:[[".",".",".",".",".",".",".","."],
[".",".",".","p",".",".",".","."],
[".",".",".","p",".",".",".","."],
["p","p",".","R",".","p","B","."],
[".",".",".",".",".",".",".","."],
[".",".",".","B",".",".",".","."],
[".",".",".","p",".",".",".","."],
[".",".",".",".",".",".",".","."]]
輸出:3
解釋: 
車可以捕獲位置 b5,d6 和 f5 的卒。

提示:

board.length == board[i].length == 8
board[i][j] 可以是 ‘R’,’.’,‘B’ 或 ‘p’
只有一個格子上存在 board[i][j] == ‘R’

方法一:

https://leetcode-cn.com/problems/available-captures-for-rook/solution/mo-ni-ti-an-zhao-ti-mu-yi-si-shi-xian-ji-ke-java-b/

class Solution {
    public int numRookCaptures(char[][] board) {
        // 因爲題目已經明確給出 board.length == board[i].length == 8,所以不做輸入檢查
        // 定義方向數組,可以認爲是四個方向向量,在棋盤問題上是常見的做法
        int[][] directions = {{-1, 0}, {1, 0}, {0, 1}, {0, -1}};

        for (int i = 0; i < 8; i++) {
            for (int j = 0; j < 8; j++) {              
                if (board[i][j] == 'R') {
                    int res = 0;
                    for (int[] direction : directions) {
                        if (burnout(board, i, j, direction)) {
                            res++;
                        }
                    }
                    return res;
                }
            }
        }
        // 代碼不會走到這裏,返回 0 或者拋出異常均可
        return 0;
    }

    /**
     * burnout 橫衝直撞的意思(來自歐路詞典)
     *
     * @param board     輸入棋盤
     * @param x         當前白象位置的橫座標
     * @param y         當前白象位置的縱座標
     * @param direction 方向向量
     * @return 消滅一個 p,就返回 true
     */
    private boolean burnout(char[][] board, int x, int y, int[] direction) {
        int i = x;
        int j = y;
        while (inArea(i, j)) {
            // 是友軍,路被堵死,直接返回
            if (board[i][j] == 'B') {
                break;
            }

            // 是敵軍,拿下一血(不知道一血這個詞是不是這麼用的)
            if (board[i][j] == 'p') {
                return true;
            }

            i += direction[0];
            j += direction[1];
        }
        return false;
    }

    /**
     * @param i 當前位置橫座標
     * @param j 當前位置縱座標
     * @return 是否在棋盤有效範圍內
     */
    private boolean inArea(int i, int j) {
        return i >= 0 && i < 8 && j >= 0 && j < 8;
    }
}

[0073]從上到下打印二叉樹 II

從上到下按層打印二叉樹,同一層的節點按從左到右的順序打印,每一層打印到一行。

例如:
給定二叉樹: [3,9,20,null,null,15,7],

		3
   / \
  9  20
    /  \
   15   7

返回其層次遍歷結果:

[
  [3],
  [9,20],
  [15,7]
]

提示:

節點總數 <= 1000

方法一:隊列

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        Queue<TreeNode> queue = new LinkedList<>();
        List<List<Integer>> res = new ArrayList<>();
        if(root != null) queue.add(root);
        while(!queue.isEmpty()) {
            List<Integer> tmp = new ArrayList<>();
            for(int i = queue.size(); i > 0; i--) {
                TreeNode node = queue.poll();
                tmp.add(node.val);
                if(node.left != null) queue.add(node.left);
                if(node.right != null) queue.add(node.right);
            }
            res.add(tmp);
        }
        return res;     
    }
}

方法二:遞歸

class Solution {
    List<List<Integer>> res = new ArrayList();
    public List<List<Integer>> levelOrder(TreeNode root){
        recur(root,0);
        return res;
    }
    public void recur(TreeNode root,int k){
        if(root != null){
            if(res.size() <= k)
                res.add(new ArrayList());
            res.get(k).add(root.val);
            recur(root.left,k+1);
            recur(root.right,k+1);
        }
    }
}

[0074]逐步求和得到正數的最小值

給你一個整數數組 nums 。你可以選定任意的 正數 startValue 作爲初始值。

你需要從左到右遍歷 nums 數組,並將 startValue 依次累加上 nums 數組中的值。

請你在確保累加和始終大於等於 1 的前提下,選出一個最小的 正數 作爲 startValue 。

示例 1:

輸入:nums = [-3,2,-3,4,2]
輸出:5
解釋:如果你選擇 startValue = 4,在第三次累加時,和小於 1 。
                累加求和
                startValue = 4 | startValue = 5 | nums
                  (4 -3 ) = 1  | (5 -3 ) = 2    |  -3
                  (1 +2 ) = 3  | (2 +2 ) = 4    |   2
                  (3 -3 ) = 0  | (4 -3 ) = 1    |  -3
                  (0 +4 ) = 4  | (1 +4 ) = 5    |   4
                  (4 +2 ) = 6  | (5 +2 ) = 7    |   2

示例 2:

輸入:nums = [1,2]
輸出:1
解釋:最小的 startValue 需要是正數。

示例 3:

輸入:nums = [1,-2,-3]
輸出:5

提示:

1 <= nums.length <= 100
-100 <= nums[i] <= 100

方法一:

找一個開始值,然後以這個值開始加數組中的每一個數,中間每一步都要大於 1。

加每一個數就是前綴和。

如果要每一步都大於 1 ,只需要找到前綴和中最小的值。

class Solution {
    public int minStartValue(int[] nums) {
        int sum = 0;
        int min = Integer.MAX_VALUE;
        for (int i = 0; i < nums.length; i++) {
            sum += nums[i];
            if (sum < min) {
                min = sum;
            }
        }
        return Math.max(1, 1 - min);
    }
}

[0075]拼寫單詞

給你一份『詞彙表』(字符串數組) words 和一張『字母表』(字符串) chars。

假如你可以用 chars 中的『字母』(字符)拼寫出 words 中的某個『單詞』(字符串),那麼我們就認爲你掌握了這個單詞。

注意:每次拼寫(指拼寫詞彙表中的一個單詞)時,chars 中的每個字母都只能用一次。

返回詞彙表 words 中你掌握的所有單詞的 長度之和。

示例 1:

輸入:words = ["cat","bt","hat","tree"], chars = "atach"
輸出:6
解釋: 
可以形成字符串 "cat" 和 "hat",所以答案是 3 + 3 = 6。

示例 2:

輸入:words = ["hello","world","leetcode"], chars = "welldonehoneyr"
輸出:10
解釋:
可以形成字符串 "hello" 和 "world",所以答案是 5 + 5 = 10。

提示:

1 <= words.length <= 1000
1 <= words[i].length, chars.length <= 100
所有字符串中都僅包含小寫英文字母

方法一:

class Solution {
    public int countCharacters(String[] words, String chars) {
        int[] chars_count = count(chars); // 統計字母表的字母出現次數
        int res = 0;
        for (String word : words) {
            int[] word_count = count(word); // 統計單詞的字母出現次數
            if (contains(chars_count, word_count)) {
                res += word.length();
            }
        }
        return res;
    }

    // 檢查字母表的字母出現次數是否覆蓋單詞的字母出現次數
    boolean contains(int[] chars_count, int[] word_count) {
        for (int i = 0; i < 26; i++) {
            if (chars_count[i] < word_count[i]) {
                return false;
            }
        }
        return true;
    }

    // 統計 26 個字母出現的次數
    int[] count(String word) {
        int[] counter = new int[26];
        for (int i = 0; i < word.length(); i++) {
            char c = word.charAt(i);
            counter[c-'a']++;
        }
        return counter;
    }
}

[0076]N叉樹的最大深度

給定一個 N 叉樹,找到其最大深度。

最大深度是指從根節點到最遠葉子節點的最長路徑上的節點總數。

例如,給定一個 3叉樹 :

img

我們應返回其最大深度,3。

說明:

樹的深度不會超過 1000。
樹的節點總不會超過 5000。

方法一:遞歸

/*
// Definition for a Node.
class Node {
    public int val;
    public List<Node> children;

    public Node() {}

    public Node(int _val) {
        val = _val;
    }

    public Node(int _val, List<Node> _children) {
        val = _val;
        children = _children;
    }
};
*/
class Solution {
  public int maxDepth(Node root) {
    if (root == null) {
      return 0;
    } else if (root.children.isEmpty()) {
      return 1;  
    } else {
      List<Integer> heights = new LinkedList<>();
      for (Node item : root.children) {
        heights.add(maxDepth(item)); 
      }
      return Collections.max(heights) + 1;
    }
  }
}

方法二: 迭代

class Solution {
  public int maxDepth(Node root) {
    Queue<Pair<Node, Integer>> stack = new LinkedList<>();
    if (root != null) {
      stack.add(new Pair(root, 1));
    }

    int depth = 0;
    while (!stack.isEmpty()) {
      Pair<Node, Integer> current = stack.poll();
      root = current.getKey();
      int current_depth = current.getValue();
      if (root != null) {
        depth = Math.max(depth, current_depth);
        for (Node c : root.children) {
          stack.add(new Pair(c, current_depth + 1));    
        }
      }
    }
    return depth;
  }
}

[0077]刪列造序

給定由 N 個小寫字母字符串組成的數組 A,其中每個字符串長度相等。

你需要選出一組要刪掉的列 D,對 A 執行刪除操作,使 A 中剩餘的每一列都是 非降序 排列的,然後請你返回 D.length 的最小可能值。

刪除 操作的定義是:選出一組要刪掉的列,刪去 A 中對應列中的所有字符,形式上,第 n 列爲[A[0][n], A[1][n], ..., A[A.length-1][n]]

比如,有A = ["abcdef", "uvwxyz"]

img

要刪掉的列爲 {0, 2, 3},刪除後 A 爲[“bef”, “vyz”], A 的列分別爲[“b”,“v”], [“e”,“y”], [“f”,“z”]。

img

示例 1:

輸入:["cba", "daf", "ghi"]
輸出:1
解釋:
當選擇 D = {1},刪除後 A 的列爲:["c","d","g"] 和 ["a","f","i"],均爲非降序排列。
若選擇 D = {},那麼 A 的列 ["b","a","h"] 就不是非降序排列了。

示例 2:

輸入:["a", "b"]
輸出:0
解釋:D = {}

示例 3:

輸入:["zyx", "wvu", "tsr"]
輸出:3
解釋:D = {0, 1, 2}

提示:

1 <= A.length <= 100
1 <= A[i].length <= 1000

方法一:

class Solution {
    public int minDeletionSize(String[] A) {
        int ans = 0;
        for (int c = 0; c < A[0].length(); ++c)
            for (int r = 0; r < A.length - 1; ++r)
                if (A[r].charAt(c) > A[r+1].charAt(c)) {
                    ans++;
                    break;
                }

        return ans;
    }
}

[0078]兩個數組的交集

給定兩個數組,編寫一個函數來計算它們的交集。

示例 1:

輸入: nums1 = [1,2,2,1], nums2 = [2,2]
輸出: [2]

示例 2:

輸入: nums1 = [4,9,5], nums2 = [9,4,9,8,4]
輸出: [9,4]

說明:

輸出結果中的每個元素一定是唯一的。
我們可以不考慮輸出結果的順序。

方法一:set

class Solution {
  public int[] set_intersection(HashSet<Integer> set1, HashSet<Integer> set2) {
    int [] output = new int[set1.size()];
    int idx = 0;
    for (Integer s : set1)
      if (set2.contains(s)) output[idx++] = s;

    return Arrays.copyOf(output, idx);
  }

  public int[] intersection(int[] nums1, int[] nums2) {
    HashSet<Integer> set1 = new HashSet<Integer>();
    for (Integer n : nums1) set1.add(n);
    HashSet<Integer> set2 = new HashSet<Integer>();
    for (Integer n : nums2) set2.add(n);

    if (set1.size() < set2.size()) return set_intersection(set1, set2);
    else return set_intersection(set2, set1);
  }
}

方法二:內置函數

class Solution {
  public int[] intersection(int[] nums1, int[] nums2) {
    HashSet<Integer> set1 = new HashSet<Integer>();
    for (Integer n : nums1) set1.add(n);
    HashSet<Integer> set2 = new HashSet<Integer>();
    for (Integer n : nums2) set2.add(n);

    set1.retainAll(set2);

    int [] output = new int[set1.size()];
    int idx = 0;
    for (int s : set1) output[idx++] = s;
    return output;
  }
}

[0079]鏈表的中間結點

給定一個帶有頭結點 head 的非空單鏈表,返回鏈表的中間結點。

如果有兩個中間結點,則返回第二個中間結點。

示例 1:

輸入:[1,2,3,4,5]
輸出:此列表中的結點 3 (序列化形式:[3,4,5])
返回的結點值爲 3 。 (測評系統對該結點序列化表述是 [3,4,5])。
注意,我們返回了一個 ListNode 類型的對象 ans,這樣:
ans.val = 3, ans.next.val = 4, ans.next.next.val = 5, 以及 ans.next.next.next = NULL.

示例 2:

輸入:[1,2,3,4,5,6]
輸出:此列表中的結點 4 (序列化形式:[4,5,6])
由於該列表有兩個中間結點,值分別爲 3 和 4,我們返回第二個結點。

提示:

給定鏈表的結點數介於 1 和 100 之間。

方法一: 雙指針

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode middleNode(ListNode head) {
        ListNode slow = head, fast = head;
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
        }
        return slow;
    }
}

方法二:數組

class Solution {
    public ListNode middleNode(ListNode head) {
        ListNode[] A = new ListNode[100];
        int t = 0;
        while (head != null) {
            A[t++] = head;
            head = head.next;
        }
        return A[t / 2];
    }
}

[0080]鍵盤行

給定一個單詞列表,只返回可以使用在鍵盤同一行的字母打印出來的單詞。鍵盤如下圖所示。

示例:

輸入: ["Hello", "Alaska", "Dad", "Peace"]
輸出: ["Alaska", "Dad"]

注意:

你可以重複使用鍵盤上同一字符。
你可以假設輸入的字符串將只包含字母。

方法一:

class Solution {
    public String[] findWords(String[] words) {
		//首先把3行鍵盤表示出來
		String[] lines= {
				"qwertyuiopQWERTYUIOP",
				"asdfghjklASDFGHJKL",
				"zxcvbnmZXCVBNM"
		};
		//定義一箇中間儲存數組pre來儲存滿足條件的單詞,長度就爲輸入數組的長度
		String[] pre= new String[words.length];
		//定義t來儲存滿足題目意思的單詞數
		//也爲了pre的開始下標爲0
		int t=0;
		//下面這個for循環用來一個個單詞逐個判斷
		for(int i=0;i<words.length;i++) {
			String temp="";//定義一個臨時的字符串來存儲這3行的某一行
			int count=0;//定義一個count來儲存當前單詞滿足的字母個數
			//下面這個循環來遍歷當前單詞的每一個字母
			for(int j=0;j<words[i].length();j++) {

				//如果當前單詞的首字母在第某行,臨時字符串temp就等於第某行
				if(lines[0].indexOf(words[i].charAt(0))!=-1) {
					temp=lines[0];
				}else if(lines[1].indexOf(words[i].charAt(0))!=-1) {
					temp=lines[1];
				}else {
					temp=lines[2];
				}
				//前面已經知道這個單詞是在第幾行了,所以現在要遍歷每個字母也是否在這一行
				//並且滿足的單詞個數count也要+1
				if(temp.indexOf(words[i].charAt(j))==-1){
					break;
				}else {
					count++;
				}
				//如果滿足的單詞個數等於當前單詞的長度
				//所以用中間儲存數組pre來存儲此單詞,並且t也要+1
				//意味着現在長度爲t ,也就是滿足的單詞個數爲t
				if(count==words[i].length()) {
					pre[t]=words[i];
					t++;
				}
			}	
		}
		//最後一步,定義一個數組res來儲存pre中的元素
		//並且長度爲t
		String[] res = new String[t];
		for(int i=0;i<t;i++) {
			res[i]=pre[i];
		}
		return res;
    }
}

方法二:

class Solution {
    public String[] findWords(String[] words) {
        if(words==null||words.length==0) return new String[0];
        //用長度爲26的數組標識每個字母所在的行號
        int[] map = {2,3,3,2,1,2,2,2,1,2,2,2,3,3,1,1,1,1,2,1,1,3,1,3,1,3};
        List<String> list = new ArrayList<String>();
        for(String word:words){
            String tempWord = word.toUpperCase();
            int temp = map[tempWord.charAt(0)-65];
            boolean flag = true;
            //通過與首字母比較行號確定是否在同一行
            for(int i=1;i<tempWord.length();i++){
                if(temp != map[tempWord.charAt(i)-65]){
                    flag = false;
                    break;
                }
            }
            if(flag) list.add(word);
        }
        return list.toArray(new String[list.size()]);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章