[0049]二進制中1的個數
請實現一個函數,輸入一個整數,輸出該數二進制表示中 1 的個數。例如,把 9 表示成二進制是 1001,有 2 位是 1。因此,如果輸入 9,則該函數輸出 2。
示例 1:
輸入:00000000000000000000000000001011
輸出:3
解釋:輸入的二進制串 00000000000000000000000000001011 中,共有三位爲 '1'。
示例 2:
輸入:00000000000000000000000010000000
輸出:1
解釋:輸入的二進制串 00000000000000000000000010000000 中,共有一位爲 '1'。
示例 3:
輸入:11111111111111111111111111111101
輸出:31
解釋:輸入的二進制串 11111111111111111111111111111101 中,共有 31 位爲 '1'。
方法一:循環和位移動
public class Solution {
// you need to treat n as an unsigned value
public int hammingWeight(int n) {
int bits = 0;
int mask = 1;
for (int i = 0; i < 32; i++) {
if( (n & mask) != 0) bits++;
mask <<= 1;
}
return bits;
}
}
方法 2:位操作的小技巧
public class Solution {
// you need to treat n as an unsigned value
public int hammingWeight(int n) {
int sum = 0;
while (n != 0) {
sum++;
n &= (n - 1);
}
return sum;
}
}
[0050]高度檢查器
學校在拍年度紀念照時,一般要求學生按照 非遞減 的高度順序排列。
請你返回能讓所有學生以 非遞減 高度排列的最小必要移動人數。
注意,當一組學生被選中時,他們之間可以以任何可能的方式重新排序,而未被選中的學生應該保持不動。
示例:
輸入:heights = [1,1,4,2,1,3]
輸出:3
解釋:
當前數組:[1,1,4,2,1,3]
目標數組:[1,1,1,2,3,4]
在下標 2 處(從 0 開始計數)出現 4 vs 1 ,所以我們必須移動這名學生。
在下標 4 處(從 0 開始計數)出現 1 vs 3 ,所以我們必須移動這名學生。
在下標 5 處(從 0 開始計數)出現 3 vs 4 ,所以我們必須移動這名學生。
示例 2:
輸入:heights = [5,1,2,3,4]
輸出:5
示例 3:
輸入:heights = [1,2,3,4,5]
輸出:0
提示:
1 <= heights.length <= 100
1 <= heights[i] <= 100
實際上是:對比排序後和排序前位置不一樣的個數
方法一:計數算法
class Solution {
public int heightChecker(int[] heights) {
// 值的範圍是1 <= heights[i] <= 100,因此需要1,2,3,...,99,100,共101個桶
int[] arr = new int[101];
// 遍歷數組heights,計算每個桶中有多少個元素,也就是數組heights中有多少個1,多少個2,。。。,多少個100
// 將這101個桶中的元素,一個一個桶地取出來,元素就是有序的
for (int height : heights) {
arr[height]++;
}
int count = 0;
for (int i = 1, j = 0; i < arr.length; i++) {
// arr[i],i就是桶中存放的元素的值,arr[i]是元素的個數
// arr[i]-- 就是每次取出一個,一直取到沒有元素,成爲空桶
while (arr[i]-- > 0) {
// 從桶中取出元素時,元素的排列順序就是非遞減的,然後與heights中的元素比較,如果不同,計算器就加1
if (heights[j++] != i) count++;
}
}
return count;
}
}
時間複雜度:O(n)
空間複雜度:O(1)
方法二:排序
class Solution {
public int heightChecker(int[] heights) {
int[] temp = heights.clone();
Arrays.sort(temp);
int cnt=0;
for (int i = 0; i <heights.length ; i++) {
if (temp[i]!=heights[i]) cnt++;
}
return cnt;
}
}
時間複雜度:O(NlogN)
空間複雜度:O(N)
[0051]自除數
自除數 是指可以被它包含的每一位數除盡的數。
例如,128 是一個自除數,因爲 128 % 1 == 0,128 % 2 == 0,128 % 8 == 0。
還有,自除數不允許包含 0 。
給定上邊界和下邊界數字,輸出一個列表,列表的元素是邊界(含邊界)內所有的自除數。
示例 1:
輸入:
上邊界left = 1, 下邊界right = 22
輸出: [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 15, 22]
注意:
每個輸入參數的邊界滿足 1 <= left <= right <= 10000。
方法一:
class Solution {
public List<Integer> selfDividingNumbers(int left, int right) {
List<Integer> ans = new ArrayList();
for (int n = left; n <= right; ++n) {
if (selfDividing(n)) ans.add(n);
}
return ans;
}
public boolean selfDividing(int n) {
for (char c: String.valueOf(n).toCharArray()) {
if (c == '0' || (n % (c - '0') > 0))
return false;
}
return true;
}
/*
Alternate implementation of selfDividing:
public boolean selfDividing(int n) {
int x = n;
while (x > 0) {
int d = x % 10;
x /= 10;
if (d == 0 || (n % d) > 0) return false;
}
return true;
*/
}
[0052]二叉搜索樹中的搜索
給定二叉搜索樹(BST)的根節點和一個值。 你需要在BST中找到節點值等於給定值的節點。 返回以該節點爲根的子樹。 如果節點不存在,則返回 NULL。
例如,
給定二叉搜索樹:
4
/ \
2 7
/ \
1 3
和值: 2
你應該返回如下子樹:
2
/ \
1 3
在上述示例中,如果要找的值是 5,但因爲沒有節點值爲 5,我們應該返回 NULL。
方法一:遞歸
/**
* 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 || val == root.val) return root;
return val < root.val ? searchBST(root.left, val) : searchBST(root.right, val);
}
}
時間複雜度:O(H),其中 H 是樹高。平均時間複雜度爲 O(logN),最壞時間複雜度爲 O(N)。
空間複雜度:O(H),遞歸棧的深度爲H。平均情況下深度爲 O(logN),最壞情況下深度爲 O(N)。
方法二:迭代
時間複雜度:O(H),其中 H 是樹高。平均時間複雜度爲 O(logN),最壞時間複雜度爲 O(N)。
空間複雜度:O(1),恆定的額外空間。
[0053]N叉樹的後序遍歷
給定一個 N 叉樹,返回其節點值的後序遍歷。
例如,給定一個 3叉樹 :
返回其後序遍歷: [5,6,3,2,4,1].
說明: 遞歸法很簡單,你可以使用迭代法完成此題嗎?
方法一:
/*
// 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 {
List<Integer> res = new ArrayList<Integer>();
public List<Integer> postorder(Node root) {
dfs(root);
return res;
}
public void dfs(Node root) {
if(root == null) return;
for(Node child : root.children)
dfs(child);
res.add(root.val);
}
}
方法二:
class Solution {
public List<Integer> postorder(Node root) {
LinkedList<Node> stack = new LinkedList<>();
LinkedList<Integer> output = new LinkedList<>();
if (root == null) {
return output;
}
stack.add(root);
while (!stack.isEmpty()) {
Node node = stack.pollLast();
output.addFirst(node.val); //在第一個位置add
for (Node item : node.children) {
if (item != null) {
stack.add(item);
}
}
}
return output;
}
}
[0054]二叉樹的最大深度
給定一個二叉樹,找出其最大深度。
二叉樹的深度爲根節點到最遠葉子節點的最長路徑上的節點數。
說明: 葉子節點是指沒有子節點的節點。
示例:
給定二叉樹 [3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
返回它的最大深度 3 。
方法一:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public int maxDepth(TreeNode root) {
if (root == null) {
return 0;
} else {
int left_height = maxDepth(root.left);
int right_height = maxDepth(root.right);
return Math.max(left_height, right_height) + 1;
}
}
}
方法二:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public int maxDepth(TreeNode root) {
if (root == null) {
return 0;
}
// bfs
Queue<TreeNode> queue = new LinkedList<>();
int depth = 0;
queue.add(root);
while (!queue.isEmpty()) {
int size = queue.size();
depth++;
for (int i = 0; i < size; i++) {
TreeNode temp = queue.poll();
if (temp.left != null) {
queue.add(temp.left);
}
if (temp.right != null) {
queue.add(temp.right);
}
}
}
return depth;
}
}
[0055]N叉樹的前序遍歷
給定一個 N 叉樹,返回其節點值的前序遍歷。
例如,給定一個 3叉樹
:
返回其前序遍歷: [1,3,5,6,2,4]
。
方法一:
/*
// 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 {
List<Integer> res = new ArrayList<Integer>();
public List<Integer> preorder(Node root) {
dfs(root);
return res;
}
public void dfs(Node root) {
if(root == null) return;
res.add(root.val);
for(Node child : root.children)
dfs(child);
}
}
方法二:
class Solution {
public List<Integer> preorder(Node root) {
LinkedList<Node> stack = new LinkedList<>();
LinkedList<Integer> output = new LinkedList<>();
if (root == null) {
return output;
}
stack.add(root);
while (!stack.isEmpty()) {
Node node = stack.pollLast();
output.add(node.val);
Collections.reverse(node.children);
for (Node item : node.children) {
stack.add(item);
}
}
return output;
}
}
[0056] 判定字符是否唯一
實現一個算法,確定一個字符串 s 的所有字符是否全都不同。
示例 1:
輸入: s = "leetcode"
輸出: false
示例 2:
輸入: s = "abc"
輸出: true
限制:
0 <= len(s) <= 100
如果你不使用額外的數據結構,會很加分。
方法一:
class Solution {
public boolean isUnique(String astr) {
Set set = new HashSet();
for (int i = 0; i <astr.length() ; i++) {
set.add(astr.charAt(i));
if(set.size() < i +1 ) return false;
}
return set.size() == astr.length();
}
}
方法二:
class Solution {
public boolean isUnique(String astr) {
long low64 = 0;
long high64 = 0;
for (char c : astr.toCharArray()) {
if (c >= 64) {
long bitIndex = 1L << c - 64;
if ((high64 & bitIndex) != 0) {
return false;
}
high64 |= bitIndex;
} else {
long bitIndex = 1L << c;
if ((low64 & bitIndex) != 0) {
return false;
}
low64 |= bitIndex;
}
}
return true;
}
}
[0057]二叉搜索樹的第k大節點
給定一棵二叉搜索樹,請找出其中第k大的節點。
示例 1:
輸入: root = [3,1,4,null,2], k = 1
3
/ \
1 4
\
2
輸出: 4
示例 2:
輸入: root = [5,3,6,2,4,null,null,1], k = 3
5
/ \
3 6
/ \
2 4
/
1
輸出: 4
限制:
1 ≤ k ≤ 二叉搜索樹元素個數
方法一:遞歸
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
int res, k;
public int kthLargest(TreeNode root, int k) {
this.k = k;
dfs(root);
return res;
}
void dfs(TreeNode root) {
if(root == null) return;
dfs(root.right);
if(k == 0) return;
if(--k == 0) res = root.val;
dfs(root.left);
}
}
方法二:迭代
class Solution {
public int kthLargest(TreeNode root, int k) {
int count = 1;
Stack<TreeNode> stack = new Stack<>();
while (Objects.nonNull(root) || !stack.empty()) {
while (Objects.nonNull(root)) {
stack.push(root);
root = root.right;
}
TreeNode pop = stack.pop();
if (count == k) {
return pop.val;
}
count++;
root = pop.left;
}
return 0;
}
}
class Solution {
public int kthLargest(TreeNode root, int k) {
List<Integer> result = new LinkedList<>();
Stack<TreeNode> stack = new Stack<>();
TreeNode cur = root;
while (cur != null || !stack.isEmpty()) {
while (cur != null) {
stack.push(cur);
cur = cur.right;
}
cur = stack.pop();
result.add(cur.val);
if(result.size() == k){
return cur.val;
}
cur = cur.left;
}
return result.get(k - 1);
}
}
[0058]用兩個棧實現隊列
用兩個棧實現一個隊列。隊列的聲明如下,請實現它的兩個函數 appendTail 和 deleteHead ,分別完成在隊列尾部插入整數和在隊列頭部刪除整數的功能。(若隊列中沒有元素,deleteHead 操作返回 -1 )
示例 1:
輸入:
["CQueue","appendTail","deleteHead","deleteHead"]
[[],[3],[],[]]
輸出:[null,null,3,-1]
示例 2:
輸入:
["CQueue","deleteHead","appendTail","appendTail","deleteHead","deleteHead"]
[[],[],[5],[2],[],[]]
輸出:[null,-1,null,null,5,2]
提示:
1 <= values <= 10000
最多會對 appendTail、deleteHead 進行 10000 次調用
方法一:
class CQueue {
Stack<Integer> stack1;
Stack<Integer> stack2;
int size;
public CQueue() {
stack1 = new Stack<Integer>();
stack2 = new Stack<Integer>();
size = 0;
}
public void appendTail(int value) {
while (!stack1.isEmpty()) {
stack2.push(stack1.pop());
}
stack1.push(value);
while (!stack2.isEmpty()) {
stack1.push(stack2.pop());
}
size++;
}
public int deleteHead() {
if (size == 0) {
return -1;
}
size--;
return stack1.pop();
}
}
/**
* Your CQueue object will be instantiated and called as such:
* CQueue obj = new CQueue();
* obj.appendTail(value);
* int param_2 = obj.deleteHead();
*/
[0059]兩個數組間的距離值
給你兩個整數數組 arr1 , arr2 和一個整數 d ,請你返回兩個數組之間的 距離值 。
「距離值」 定義爲符合此描述的元素數目:
對於元素 arr1[i] ,不存在任何元素 arr2[j] 滿足 |arr1[i]-arr2[j]| <= d 。
示例 1:
輸入:arr1 = [4,5,8], arr2 = [10,9,1,8], d = 2
輸出:2
解釋:
對於 arr1[0]=4 我們有:
|4-10|=6 > d=2
|4-9|=5 > d=2
|4-1|=3 > d=2
|4-8|=4 > d=2
對於 arr1[1]=5 我們有:
|5-10|=5 > d=2
|5-9|=4 > d=2
|5-1|=4 > d=2
|5-8|=3 > d=2
對於 arr1[2]=8 我們有:
|8-10|=2 <= d=2
|8-9|=1 <= d=2
|8-1|=7 > d=2
|8-8|=0 <= d=2
示例 2:
輸入:arr1 = [1,4,2,3], arr2 = [-4,-3,6,10,20,30], d = 3
輸出:2
示例 3:
輸入:arr1 = [2,1,100,3], arr2 = [-5,-2,10,-3,7], d = 6
輸出:1
提示:
1 <= arr1.length, arr2.length <= 500
-10^3 <= arr1[i], arr2[j] <= 10^3
0 <= d <= 100
方法一:暴力
class Solution {
private int getCount(int num1, int[] arr2, int d) {
for (int num2 : arr2) {
if (Math.abs(num1 - num2) <= d) {
return 0;
}
}
return 1;
}
public int findTheDistanceValue(int[] arr1, int[] arr2, int d) {
int ans = 0;
for (int num1 : arr1) {
ans += getCount(num1, arr2, d);
}
return ans;
}
}
其他題解:
https://leetcode-cn.com/problems/find-the-distance-value-between-two-arrays/solution/1385java-liang-chong-fang-fa-er-fen-shuang-zhi-zhe/
[0060]增減字符串匹配
給定只含 “I”(增大)或 “D”(減小)的字符串 S ,令 N = S.length。
返回 [0, 1, …, N] 的任意排列 A 使得對於所有 i = 0, …, N-1,都有:
如果 S[i] == "I",那麼 A[i] < A[i+1]
如果 S[i] == "D",那麼 A[i] > A[i+1]
示例 1:
輸出:"IDID"
輸出:[0,4,1,3,2]
示例 2:
輸出:"III"
輸出:[0,1,2,3]
示例 3:
輸出:"DDI"
輸出:[3,2,0,1]
提示:
1 <= S.length <= 10000
S 只包含字符 “I” 或 “D”。
方法一:
class Solution {
public int[] diStringMatch(String S) {
int N = S.length();
int start = 0;
int end = N;
int[] res = new int[N+1];
for(int i = 0; i < N; ++i){
if (S.charAt(i) == 'I'){
res[i] = start++;
}else{
res[i] = end--;
}
}
res[N] = end;
return res;
}
}
[0061]有序數組的平方
給定一個按非遞減順序排序的整數數組 A,返回每個數字的平方組成的新數組,要求也按非遞減順序排序。
示例 1:
輸入:[-4,-1,0,3,10]
輸出:[0,1,9,16,100]
示例 2:
輸入:[-7,-3,2,3,11]
輸出:[4,9,9,49,121]
提示:
1 <= A.length <= 10000
-10000 <= A[i] <= 10000
A 已按非遞減順序排序。
方法一:
class Solution {
public int[] sortedSquares(int[] A) {
int N = A.length;
int[] ans = new int[N];
for (int i = 0; i < N; ++i)
ans[i] = A[i] * A[i];
Arrays.sort(ans);
return ans;
}
}
方法二:雙指針
class Solution {
public int[] sortedSquares(int[] A) {
int N = A.length;
int j = 0; // j 正向讀取非負數部分
while (j < N && A[j] < 0)
j++;
int i = j-1; // i 反向讀取負數部分
int[] ans = new int[N];
int t = 0;
while (i >= 0 && j < N) {
if (A[i] * A[i] < A[j] * A[j]) {
ans[t++] = A[i] * A[i];
i--;
} else {
ans[t++] = A[j] * A[j];
j++;
}
}
while (i >= 0) {
ans[t++] = A[i] * A[i];
i--;
}
while (j < N) {
ans[t++] = A[j] * A[j];
j++;
}
return ans;
}
}
[0062]矩陣中的幸運數
給你一個 m * n 的矩陣,矩陣中的數字 各不相同 。請你按 任意 順序返回矩陣中的所有幸運數。
幸運數是指矩陣中滿足同時下列兩個條件的元素:
在同一行的所有元素中最小
在同一列的所有元素中最大
示例 1:
輸入:matrix = [[3,7,8],[9,11,13],[15,16,17]]
輸出:[15]
解釋:15 是唯一的幸運數,因爲它是其所在行中的最小值,也是所在列中的最大值。
示例 2:
輸入:matrix = [[1,10,4,2],[9,3,8,7],[15,16,17,12]]
輸出:[12]
解釋:12 是唯一的幸運數,因爲它是其所在行中的最小值,也是所在列中的最大值。
示例 3:
輸入:matrix = [[7,8],[1,2]]
輸出:[7]
提示:
m == mat.length
n == mat[i].length
1 <= n, m <= 50
1 <= matrix[i][j] <= 10^5
矩陣中的所有元素都是不同的
方法一:
class Solution {
public List<Integer> luckyNumbers (int[][] matrix) {
List<Integer> res = new ArrayList<>();
for (int i = 0; i < matrix.length; i++) {
int min = Integer.MAX_VALUE;
int idx = -1;
for (int j = 0; j < matrix[0].length; j++) {
if (min > matrix[i][j]) {
idx = j;
min = matrix[i][j];
}
}
boolean flag = true;
for (int j = 0; j < matrix.length; j++) {
if (min < matrix[j][idx] && j != i) {
flag = false;
break;
}
}
if (flag) {
res.add(min);
}
}
return res;
}
}
方法二:
class Solution {
public List<Integer> luckyNumbers (int[][] matrix) {
int m = matrix.length;
int n = matrix[0].length;
int[] min = new int[m];
int[] max = new int[n];
Arrays.fill(min, Integer.MAX_VALUE);
Arrays.fill(max, Integer.MIN_VALUE);
for (int i = 0; i < m; i++){
for (int j = 0; j < n; j++){
min[i] = Math.min(min[i], matrix[i][j]);// 第i行最小值
max[j] = Math.max(max[j], matrix[i][j]);// 每一列最大值與當前值比較
}
}
List<Integer> list = new ArrayList<>();
for (int i = 0; i < m; i++){
for (int j = 0; j < n; j++){
if (min[i] == max[j])
list.add(min[i]);
}
}
return list;
}
}
[0063]生成每種字符都是奇數個的字符串
給你一個整數 n,請你返回一個含 n 個字符的字符串,其中每種字符在該字符串中都恰好出現 奇數次 。
返回的字符串必須只含小寫英文字母。如果存在多個滿足題目要求的字符串,則返回其中任意一個即可。
示例 1:
輸入:n = 4
輸出:"pppz"
解釋:"pppz" 是一個滿足題目要求的字符串,因爲 'p' 出現 3 次,且 'z' 出現 1 次。當然,還有很多其他字符串也滿足題目要求,比如:"ohhh" 和 "love"。
示例 2:
輸入:n = 2
輸出:"xy"
解釋:"xy" 是一個滿足題目要求的字符串,因爲 'x' 和 'y' 各出現 1 次。當然,還有很多其他字符串也滿足題目要求,比如:"ag" 和 "ur"。
示例 3:
輸入:n = 7
輸出:"holasss"
提示:
1 <= n <= 500
方法一:
class Solution {
public String generateTheString(int n) {
StringBuilder sb = new StringBuilder();
if (n % 2 == 0) {
for (int i = 0; i < n - 1; i++)
sb.append('a');
sb.append('b');
} else {
for (int i = 0; i < n; i++)
sb.append('a');
}
return sb.toString();
}
}
[0064]最近的請求次數
寫一個 RecentCounter 類來計算最近的請求。
它只有一個方法:ping(int t),其中 t 代表以毫秒爲單位的某個時間。
返回從 3000 毫秒前到現在的 ping 數。
任何處於 [t - 3000, t] 時間範圍之內的 ping 都將會被計算在內,包括當前(指 t 時刻)的 ping。
保證每次對 ping 的調用都使用比之前更大的 t 值。
示例:
輸入:inputs = ["RecentCounter","ping","ping","ping","ping"], inputs = [[],[1],[100],[3001],[3002]]
輸出:[null,1,2,3,3]
提示:
每個測試用例最多調用 10000 次 ping。
每個測試用例會使用嚴格遞增的 t 值來調用 ping。
每次調用 ping 都有 1 <= t <= 10^9。
方法一:
class RecentCounter {
Queue<Integer> q;
public RecentCounter() {
q = new LinkedList();
}
public int ping(int t) {
q.add(t);
while (q.peek() < t - 3000)
q.poll();
return q.size();
}
}