1. 程式人生 > >【LeetCode】Day 3

【LeetCode】Day 3

文章目錄

933. Number of Recent Calls

求最近的ping請求次數(3000毫秒內)

Input: inputs = [“RecentCounter”,“ping”,“ping”,“ping”,“ping”], inputs = [[],[1],[100],[3001],[3002]]
Output: [null,1,2,3,3]
因為時間是遞增的,而題目要求輸出最近3000ms內的ping數,只需要把所有ping加到佇列中,然後把過期的刪掉,剩下的就是符合條件的。

public class RecentCounter{
	Queue<Integer> q = new LinkedList<>();
	public int ping(int t){
		q.offer(t);
		while(t - q.peek() > 3000){//從頭開始遍歷把超過3000的刪掉
			q.poll();
		}
		return q.size();
	}
}

883. Projection Area of 3D Shapes

計算三檢視投影面積之和
其中 v = grid[i][j],(i, j)表示立方體所在單元格,v表示立方體高度

Input: [[2]]
Output: 5
Explanation:[0,0]這個格子,有個高度為2的立方體,左檢視2,正檢視為2,俯檢視為1,所以面試之和為5

Input: [[1,2],[3,4]]
Output: 17
Explanation:
Here are the three projections (“shadows”) of the shape made with each axis-aligned plane.
a
[
[1, 2],
[3, 4]
]
解釋:
(0,0)有個高度為1的立方體,
(0,1)為2的立方體,
(1,0)位置有高度為3的立方體,
(1,1)位置有個高度為4的立方體
從上面看(x-y平面 ,俯視)有四個高度不為0的立方體,所以俯視圖面積為4
從正面看(x-z平面)前面有高度1,3兩個立方體,後面有2,4兩個立方體。2>1,4>3所以正試圖看到的是後面的投影面積,也就是·2+4=6
從側面看(y-z平面)前面有高度1,2兩個立方體,後面有3,4兩個立方體,3>1,4>2,所以投影面積為較大者的投影之和,即3+4=7
所以總面積為4+6+7=17
從上面可看出,正檢視求的是陣列列最大值之和,側檢視求的是陣列行最大值之和,俯檢視是非0高度元素之和。

    public int projectionArea(int[][] grid) {
        int t = 0;
        int f = 0;
        int s = 0;
        for(int row = 0, rowMax = 0, colMax = 0; row < grid.length; row++){
            for(int col = 0; col < grid[row].length; col++){
                if(rowMax < grid[row][col]){//求出每一行的最大值
                    rowMax = grid[row][col];
                }
                if(colMax < grid[col][row]){//每一列的最大值
                    colMax = grid[col][row];
                }
                if (grid[row][col] > 0) t++;//非0立方體數量
            }
            f += rowMax;//求行/列最大值之和
            s += colMax;
            //每一行和列掃描後,清0;
            rowMax = 0;
            colMax = 0;
        }
        
        return t + s + f;
    }

589. N-ary Tree Preorder Traversal

590. N-ary Tree Postorder Traversal

樹的先/後序遍歷

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

    public Node() {}

    public Node(int _val,List<Node> _children) {
        val = _val;
        children = _children;
    }
};
*/
class Solution {
    List<Integer> list = new ArrayList<>();
    //先序
    public List<Integer> preorder(Node root) {
        pre(root);
        return list;
    }
    void pre(Node node){
        if(node != null){
            list.add(node.val);//先遍歷自己
            if(node.children != null){
                for(Node n: node.children){//後遞迴遍歷子節點
                    pre(n);
                }
            }
        }
    }
    //後續
    public List<Integer> postorder(Node root) {
        post(root);
        return list;
    }
    void post(Node node){
        if(node != null){
            if(node.children != null){
                for(Node n: node.children){
                    post(n);
                }
            }
            list.add(node.val);
        }
    }
}

700. Search in a Binary Search Tree

二叉搜尋樹中搜索一個元素,返回整個子樹

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode searchBST(TreeNode root, int val) {
	    //如果當前為空或者值相等 返回當前節點。
        if(root == null || root.val == val) return root;
        if(val < root.val)//如果待搜值小於當前節點,遞迴在左子樹搜尋
            return searchBST(root.left, val);
        else
            return searchBST(root.right, val);
    }
}

908. Smallest Range I

這題題目難懂,
給一個數組A,再給一個數K,陣列中的每一個數都可以’加上(+)’ [-k,k]這個區間的一個數,得到其他新陣列。求得到的新陣列中,最大值與最小值的差值的最小值。

常規思路:
第一步: 計算出所有可能陣列
第二步: 計算出每個陣列的最大值與最小值的差值
第三部: 第二步得到的每個陣列的差值可組成一個新的陣列,求這個陣列的最小值
複雜度為O( n 2 k n^{2k} )(每個數都有2k種加減可能,n個數就會有 n 2 k n^{2k} 種情形)—放棄—

思路2:
上一種是先算出所有可能陣列再去求差,這樣可能陣列太多,不好求
這次先求出最大最小值的差,再去加(-k,k)區間的數讓這個差變小
如A = [1, 3, 6], K = 3
max = 6 , min = 1
max - min = 5
要讓差值儘可能小,那就要max儘量小,min儘量大
max = max -k能最小, min = min +k能最大;
所以max-k - (min + k) = max - min - 2*k,為最小值
而題目要求最大減最小,所以結果一定非負。
如果max-k < min+k,說明max-(-k,k),min+(-k,k)的過程會有相遇,存在差值為0的情況

public int smallestRangeI(int[] A, int K) {
	int min = A[0], max = A[0];
	for(int a: A){//遍歷找到最大最小值
	    if(a < min){
	    	min = a;
	    }else if(a > max){
	    	max = a;
	    }
	}
	return (max - k < min +k) ? 0 : (max - min - 2 * k);
}

867. Transpose Matrix

矩陣轉置。根據主對角線,翻轉矩陣

public int[][] transpose(int[][] A) {
    int[][] R = new int[A[0].length][A.length];//新建一個行列數相反的空矩陣
    for(int i = 0; i < A.length; i++){
        for(int j = 0; j< A[i].length; j++){
            R[j][i] = A[i][j];
        }
    }
    return R;
}

876. Middle of the Linked List

求一個連結串列的中間節點

這裡用兩個指標,慢指標走一步,快指標走兩步,當快指標走到終點時,慢指標剛好到中點。

    public ListNode middleNode(ListNode head) {
        ListNode sNode = head, qNode = head;
        while(qNode!=null && qNode.next != null){
            sNode = sNode.next;
            qNode = qNode.next.next;
        }
        return sNode;
    }

559. Maximum Depth of N-ary Tree

求樹的最大深度

public int maxDepth(Node root) {
    if(root == null) return 0;
    if(root.children == null) return 1;
    int max = 0;
    //遞迴求出每個子樹的最大高度,取其中最大那個
    for(Node node: root.children){
        int d = maxDepth(node);
        if(d > max) max = d;
    }
    return max + 1;
}

557. Reverse Words in a String III

字串以空格分開,倒序每一個字串

Input: “Let’s take LeetCode contest”
Output: “s’teL ekat edoCteeL tsetnoc”

先按照空格切分為字串陣列,然後對每一個字串倒序,最後再以空格連線起來。

public String reverseWords(String s) {
    String[] ss = s.split(" ");
    StringBuilder sb = new StringBuilder();
    for(int i = 0; i < ss.length; i++){
        sb.append(new StringBuilder().append(ss[i]).reverse());
        if(i < ss.length - 1){
            sb.append(" ");
        }
    }
    return sb.toString();
}

811. Subdomain Visit Count

求所有子域名訪問次數

Example 2:
Input:
[“900 google.mail.com”, “50 yahoo.com”, “1 intel.mail.com”, “5 wiki.org”]
Output:
[“901 mail.com”,“50 yahoo.com”,“900 google.mail.com”,“5 wiki.org”,“5 org”,“1 intel.mail.com”,“951 com”]
Explanation:
We will visit “google.mail.com” 900 times, “yahoo.com” 50 times, “intel.mail.com” once and “wiki.org” 5 times. For the subdomains, we will visit “mail.com” 900 + 1 = 901 times, “com” 900 + 50 + 1 = 951 times, and “org” 5 times.

public List<String> subdomainVisits(String[] cpdomains) {
    List<String> list = new ArrayList<>();
    Map<String, Integer> map = new HashMap<>();
    for (String domain : cpdomains) {
        String[] ds = domain.split(" ");//空格切分為訪問次數和訪問域名
        String[] split = ds[1].split("\\.");//點分隔開,後面的迴圈再從根域名開始拼接為子域名
        int n = Integer.parseInt(ds[0]);//訪問次數
        String s = "";
        for (int i = split.length - 1; i >= 0; i--) {
            s = split[i] + s;
            map.put(s, map.getOrDefault(s, 0) + n);//如果map種沒有就設為n,有就取出來再加上n
            s = "." + s;
        }
    }
    for (Map.Entry<String, Integer> entry : map.entrySet()) {
        list.add(entry.getValue() + " " + entry.getKey());
    }//遍歷map
    return list;
}

344. Reverse String

字串翻轉

Input: “hello”
Output: “olleh”

	//直接呼叫StringBuilder的reverse方法
	public String reverseString(String s) {
	    StringBuilder sb = new StringBuilder();
	    return sb.append(s).reverse().toString();
	}
	//首尾交換進行翻轉
    public String reverseString(String s) {
        if(s == null || s.length() == 0) return s;
        char[] cs = s.toCharArray();
        int i = 0, j = cs.length - 1;
        while(i < j){
            char t = cs[i];
            cs[i++] = cs[j];
            cs[j--] = t;
        }
        return new String(cs);
    }

806. Number of Lines To Write String

給一個長度為26的陣列表示a-z每個字母的寬度,給一個字串S
每行最多隻能容下100寬度的字元
求需要幾行,最後一行佔多少寬度。

Example :
Input:
widths = [10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10]
S = “abcdefghijklmnopqrstuvwxyz”
Output: [3, 60]
Explanation:
All letters have the same length of 10. To write all 26 letters,
we need two full lines and one line with 60 units.
3行才能容下26個字母,最後一行有6個字母佔寬6*10

public int[]numberOfLines(int[] widths, String S) {
    char[] cs = S.toCharArray();
    int line = 1, left = 0;
    for(char c: cs){
        int w = widths[c-'a'];//c字元佔的寬度
        //加上當前字元的寬度後,判斷是否大於100
        if(left + w > 100){//是的話,行數+1,最後一行的寬度初始化為w
            line++;
            left = w;
        }else{//否則繼續增加
            left += w;
        }
    }
    return new int[]{line, left};
}

476. Number Complement

求一個數字的補充數(反碼)

	
    public int findComplement(int num) {
        int a = 1;
        //計算出比num高的最小2的倍數
        //這方法leetcode執行超時,也不知道為什麼
        while(a <= num){//比如num = 5(0b101),a = 8(0b1000)
            a <<= 1;
        }
        //下面這個就沒超時
        //int c = num;
        //while(c != 0){
        //	c >>= 1;
        //	a <<= 1;
        //}
        return a - 1 - num;//a - 1 = 0b111
    }