LeetCode习题集 有些题可能直接略过了,整理一下之前刷leetcode

421. 数组中两个数的最大异或值

给定一个非空数组,数组中元素为 a0, a1, a2, … , an-1,其中 0 ≤ ai < 231 。

找到 ai 和aj 最大的异或 (XOR) 运算结果,其中0 ≤ i, j < n 。

你能在O(n)的时间解决这个问题吗?

示例:

输入: [3, 10, 5, 25, 2, 8]

输出: 28

解释: 最大的结果是 5 ^ 25 = 28.

	经典前缀树
class Solution {
      
    class TrieNode {

        TrieNode zero;

        TrieNode one;

        int val;

        TrieNode() {

        }
    }

    class Trie {

        TrieNode root;

        Trie() {
            root = new TrieNode();
        }

        void insert(int num) {
            TrieNode node = root;
            for (int i = 31; i >= 0; i--) {
                int bit = num & (1 << i);
                if (bit == 0) {
                    if (node.zero == null) {
                        node.zero = new TrieNode();
                    }
                    node = node.zero;
                } else {
                    if (node.one == null) {
                        node.one = new TrieNode();
                    }
                    node = node.one;
                }
            }
            node.val = num;
        }

        int find(int num) {
            TrieNode node = root;
            for (int i = 31; i >= 0; i--) {
                int bit = num & (1 << i);
                if (bit == 0) {
                    node = node.one == null ? node.zero : node.one;
                } else {
                    node = node.zero == null ? node.one : node.zero;
                }
            }
            return node.val;
        }
    }

    // 数组中两个数的最大异或值
    public int findMaximumXOR(int[] nums) {
        Trie trie = new Trie();
        for (int num : nums) {
            trie.insert(num);
        }
        int res = 0;
        for (int num : nums) {
            int other = trie.find(num);
            res = Math.max(res, num ^ other);
        }
        return res;
    }
}

423. 从英文中重建数字

给定一个非空字符串,其中包含字母顺序打乱的英文单词表示的数字0-9。按升序输出原始的数字。

注意:

输入只包含小写英文字母。 输入保证合法并可以转换为原始的数字,这意味着像 "abc" 或 "zerone" 的输入是不允许的。 输入字符串的长度小于 50,000。 示例 1:

输入: "owoztneoer"

输出: "012" (zeroonetwo) 示例 2:

输入: "fviefuro"

输出: "45" (fourfive)

PS: 我认为这是leetcode第一个问题描述和测试用例一样的

b( ̄▽ ̄)d

统计每个字符的字符数量
然后把每个数字的英文需要的字符算出来,02468这几个英文单词都有一个特别的字符
剩下的单词根据规律可以推出来,剩下的每个英文单词需要的字符

主要就是找英文单词中,每个数字单词的特点

class Solution {
      public String originalDigits(String s) {
        int[] wordCnt = new int[26];
        for (char c : s.toCharArray()) {
            wordCnt[c - 'a']++;
        }

        int[] numCnt = new int[10];
        numCnt[0] = wordCnt['z' - 'a'];
        numCnt[2] = wordCnt['w' - 'a'];
        numCnt[4] = wordCnt['u' - 'a'];
        numCnt[6] = wordCnt['x' - 'a'];
        numCnt[8] = wordCnt['g' - 'a'];

        numCnt[1] = wordCnt['o' - 'a'] - numCnt[0] - numCnt[2] - numCnt[4];
        numCnt[3] = wordCnt['h' - 'a'] - numCnt[8];
        numCnt[5] = wordCnt['f' - 'a'] - numCnt[4];
        numCnt[7] = wordCnt['s' - 'a'] - numCnt[6];

        numCnt[9] = wordCnt['i' - 'a'] - numCnt[5] - numCnt[6] - numCnt[8];

        int len = 0;
        for (int c : numCnt) {
            len += c;
        }        
        char[] res = new char[len];
        
        len = 0;
        for (int i = 0; i <= 9; i++) {
            for (int j = 0; j < numCnt[i]; j++) {
                res[len++] = (char)('0' + i);
            }
        }

        return new String(res);
    }
}

424. 替换后的最长重复字符

给你一个仅由大写英文字母组成的字符串,你可以将任意位置上的字符替换成另外的字符,总共可最多替换 k 次。在执行上述操作后,找到包含重复字母的最长子串的长度。

注意: 字符串长度 和 k 不会超过 104。

示例 1:

输入: s = "ABAB", k = 2

输出: 4

解释: 用两个'A'替换为两个'B',反之亦然。 示例 2:

输入: s = "AABABBA", k = 1

输出: 4

解释: 将中间的一个'A'替换为'B',字符串变为 "AABBBBA"。 子串 "BBBB" 有最长重复字母, 答案为 4。

滑动窗口
    每次找最大的,右指针的数量+k,或者以前的,保存这个最长滑动窗口的长度
        (右指针右移的时候把新结点的字符放到滑动窗口里面了)
    如果超过最大长度了,就把左指针右移,把左指针对应的字符在滑动窗口内删去
    
    到最后找和字符串长度最小的,防止k的数量大于字符串长度
class Solution {
     public int characterReplacement(String s, int k) {
        char[] chars = s.toCharArray();
        int width = 0;
        for (int left = 0, right = 0, counts[] = new int[26]; right < chars.length; right++) {
            width = Math.max(width, ++counts[chars[right] - 'A'] + k);
            while (right - left + 1 > width)
                counts[chars[left++] - 'A']--;
        }
        return Math.min(chars.length, width);
    }
}

427. 建立四叉树

我们想要使用一棵四叉树来储存一个 N x N 的布尔值网络。网络中每一格的值只会是真或假。树的根结点代表整个网络。对于每个结点, 它将被分等成四个孩子结点直到这个区域内的值都是相同的.

每个结点还有另外两个布尔变量: isLeaf 和 val。isLeaf 当这个节点是一个叶子结点时为真。val 变量储存叶子结点所代表的区域的值。

你的任务是使用一个四叉树表示给定的网络。下面的例子将有助于你理解这个问题:

给定下面这个8 x 8 网络,我们将这样建立一个对应的四叉树:

在这里插入图片描述

由上文的定义,它能被这样分割:

在这里插入图片描述

对应的四叉树应该像下面这样,每个结点由一对 (isLeaf, val) 所代表.

对于非叶子结点,val 可以是任意的,所以使用 * 代替。 在这里插入图片描述

提示:

N 将小于 1000 且确保是 2 的整次幂。 其实这个题有一些像前段时间看到得棋盘覆盖

/*
// Definition for a QuadTree node.
class Node {
    public boolean val;
    public boolean isLeaf;
    public Node topLeft;
    public Node topRight;
    public Node bottomLeft;
    public Node bottomRight;

    
    public Node() {
        this.val = false;
        this.isLeaf = false;
        this.topLeft = null;
        this.topRight = null;
        this.bottomLeft = null;
        this.bottomRight = null;
    }
    
    public Node(boolean val, boolean isLeaf) {
        this.val = val;
        this.isLeaf = isLeaf;
        this.topLeft = null;
        this.topRight = null;
        this.bottomLeft = null;
        this.bottomRight = null;
    }
    
    public Node(boolean val, boolean isLeaf, Node topLeft, Node topRight, Node bottomLeft, Node bottomRight) {
        this.val = val;
        this.isLeaf = isLeaf;
        this.topLeft = topLeft;
        this.topRight = topRight;
        this.bottomLeft = bottomLeft;
        this.bottomRight = bottomRight;
    }
};
*/
class Solution {
      public Node construct(int[][] grid) {
        return construct(grid, 0, grid.length - 1, 0, grid.length - 1);
    }

    private Node construct(int[][] grid, int top, int bottom, int left, int right) {
        for (int i = top; i <= bottom; i++) {
            for (int j = left; j <= right; j++) {
                if (grid[i][j] != grid[top][left]) {
                    Node node = new Node(false, false);
                    int mid1 = top + ((bottom - top) >> 1), mid2 = left + ((right - left) >> 1);
                    node.topLeft = construct(grid, top, mid1, left, mid2);
                    node.topRight = construct(grid, top, mid1, mid2 + 1, right);
                    node.bottomLeft = construct(grid, mid1 + 1, bottom, left, mid2);
                    node.bottomRight = construct(grid, mid1 + 1, bottom, mid2 + 1, right);
                    return node;
                }
            }
        }
        return new Node(grid[top][left] == 1, true);
    }

 
 
}

429. N叉树的层序遍历

给定一个 N 叉树,返回其节点值的层序遍历。 (即从左到右,逐层遍历)。

例如,给定一个 3叉树 :

在这里插入图片描述

返回其层序遍历:

[
     [1],
     [3,2,4],
     [5,6]
]
 

说明:

树的深度不会超过 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 List<List<Integer>> levelOrder(Node root) {
//     List<List<Integer>> res = new ArrayList<>();
//     if (root == null) return res;
//     helper(root, 0, res);
//     return res;
// }

// private void helper(Node root, int depth, List<List<Integer>> res) {
//     if (root == null) return;
//     //判断是否是新的一层
//     if (depth + 1 > res.size()) {
//         res.add(new ArrayList<>());
//     }
//     res.get(depth).add(root.val);

//     //处理子节点
//     for (Node node : root.children) {
//         if (node != null) {
//             helper(node, depth + 1, res);
//         }
//     }
// }


//队列迭代

public List<List<Integer>> levelOrder(Node root) {
    List<List<Integer>> res = new ArrayList<>();
    if (root == null) return res;
    Queue<Node> queue = new LinkedList<>();
    queue.add(root);
    while (!queue.isEmpty()) {
        int count = queue.size();
        //外层循环为一层
        List<Integer> list = new ArrayList<>();
        while (count-- > 0) {
            //将当前元素的非空子节点压入栈
            Node cur = queue.poll();
            list.add(cur.val);
            for (Node node : cur.children) {
                if (node != null) {
                    queue.add(node);
                }
            }
        }
        res.add(list);
    }
    return res;
}

 
}

430. 扁平化多级双向链表

您将获得一个双向链表,除了下一个和前一个指针之外,它还有一个子指针,可能指向单独的双向链表。这些子列表可能有一个或多个自己的子项,依此类推,生成多级数据结构,如下面的示例所示。

扁平化列表,使所有结点出现在单级双链表中。您将获得列表第一级的头部。

示例:

输入:

 1---2---3---4---5---6--NULL
         |
         7---8---9---10--NULL
             |
             11--12--NULL

输出: 1-2-3-7-8-11-12-9-10-4-5-6-NULL

以上示例的说明:

给出以下多级双向链表:

在这里插入图片描述

我们应该返回如下所示的扁平双向链表:

在这里插入图片描述

/*
// Definition for a Node.
class Node {
    public int val;
    public Node prev;
    public Node next;
    public Node child;

    public Node() {}

    public Node(int _val,Node _prev,Node _next,Node _child) {
        val = _val;
        prev = _prev;
        next = _next;
        child = _child;
    }
};
*/
class Solution {
//   public Node flatten(Node head) {
//     if (head == null) return head;
//     Node pseudoHead = new Node(0, null, head, null);

//     flattenDFS(pseudoHead, head);

//     pseudoHead.next.prev = null;
//     return pseudoHead.next;
//   }
//   public Node flattenDFS(Node prev, Node curr) {
//     if (curr == null) return prev;
//     curr.prev = prev;
//     prev.next = curr;

//     Node tempNext = curr.next;

//     Node tail = flattenDFS(curr, curr.child);
//     curr.child = null;

//     return flattenDFS(tail, tempNext);
//   }

 public Node flatten(Node head) {
    if (head == null) return head;

    Node pseudoHead = new Node(0, null, head, null);
    Node curr, prev = pseudoHead;

    Deque<Node> stack = new ArrayDeque<>();
    stack.push(head);

    while (!stack.isEmpty()) {
      curr = stack.pop();
      prev.next = curr;
      curr.prev = prev;

      if (curr.next != null) stack.push(curr.next);
      //如果有另一个链表,就入栈,下次优先遍历这个链表
      if (curr.child != null) {
        stack.push(curr.child);
        // 一定要删去子结点指针
        curr.child = null;
      }
      prev = curr;
    }
    // 将结点分离
    pseudoHead.next.prev = null;
    return pseudoHead.next;
  }
 

}