题解(01-10):link
题解(11-20):link
题解(21-30):link
题解(31-40):link
题解(41-50):link
题解(51-60): link
题解(61-67): link
题目描述: 输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
>>
:表示右移,如果该数为正,则高位补0,如果为负数,则高位补1。此时的右移就是除2操作>>>
:表示无符号右移,也叫逻辑右移。如果该数为正,则高位补0,如果该数为负数,则右移后高位同样补0。此时的负数右移就不是单纯的除2操作了public class Solution {
public int NumberOf1(int n) {
int res = 0;
// int 一共32位,每一位看看是不是1,然后向右移动32次
for (int i = 0;i < 32;i ++) {
if ((n & 1) == 1)
res ++;
n = n >>> 1;
}
return res;
}
}
n & (n - 1)
消去最后的一位1public class Solution {
public int NumberOf1(int n) {
int count = 0;
while (n != 0) {
count ++;
// 利用 n & (n - 1)可以消去n最后的一位1
n = n & (n - 1);
}
return count;
}
}
题目描述: 给定一个
double
类型的浮点数base
和int
类型的整数exponent
。求base
的exponent
次方。保证
base
和exponent
不同时为0
public class Solution {
// leetcode 上 pow(x, n)
public double Power(double base, int exponent) {
// 避免出现 exponent = Integer.MIN_VALUE 这个值带来的问题
long N = exponent;
// 先将指数化为正的,基数化为倒数。结果不变
if (exponent < 0) {
// 这个地方N取-N非常容易犯错
// 如果N = -n,那么-n会导致整型溢出,最终结果还是-n
// 赋值的过程有三步
//1.先取得n的值
//2.将n进行取相反数,这个时候就会溢出了
//3.将取反之后的值赋给N,前一步已经出现问题了
N = -N;
base = 1 / base;
}
return fastPow(base, N);
}
private double fastPow(double x, long N) {
if (N == 0) return 1;
if (N == 1) return x;
// 先计算一半,根据上面的公式返回结果值
double half = fastPow(x, N / 2);
// 如果指数为奇数返回什么,如果是偶数又返回什么。
return N % 2 == 1 ? half * half * x : half * half;
}
}
public class Solution {
// leetcode 上 pow(x, n)
public double Power(double base, int exponent) {
// 避免出现 exponent = Integer.MIN_VALUE 这个值带来的问题
long N = exponent;
if (exponent < 0) {
N = -N;
base = 1 / base;
}
double res = 1.0, curr = base;
for (long i = N;i > 0;i /= 2) {
if (i % 2 == 1) res = res * curr;
curr = curr * curr;
}
return res;
}
}
题目描述: 输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。
public class Solution {
public void reOrderArray(int [] array) {
int[] res = new int[array.length];
int front = 0, tail = array.length - 1;
// 获得奇数放到辅助数组前面
for (int i = 0;i < array.length;i ++)
if (array[i] % 2 == 1)
res[front ++] = array[i];
// 取得偶数放到辅助数组后面
for (int j = array.length - 1;j >= 0;j --)
if (array[j] % 2 == 0)
res[tail --] = array[j];
for (int k = 0;k < res.length;k ++)
array[k] = res[k];
}
}
public class Solution {
public void reOrderArray(int [] array) {
if (array == null || array.length == 0) return;
for (int i = 0;i < array.length;i ++) {
for (int j = 0;j < array.length - 1 - i;j ++) {
// 依次把偶数沉到数组末尾去
while (array[j] % 2 == 0 && array[j + 1] % 2 == 1) {
int tmp = array[j];
array[j] = array[j + 1];
array[j + 1] = tmp;
}
}
}
}
}
题目描述: 输入一个链表,输出该链表中倒数第k个结点。
public class Solution {
public ListNode FindKthToTail(ListNode head,int k) {
Map<Integer, ListNode> map = new HashMap<>();
int index = 0;
while (head != null) {
map.put(index ++, head);
head = head.next;
}
// 如果index = 0,说明 head 为空
if (index == 0 || k > size) return null;
// 第index - k 个元素就是倒数第k个元素
return map.get(index - k);
}
}
k
步,要是走不到,说明链表长度不够k
,返回null
即可k
步之后,慢指针和快指针一起往后走,当快指针走到最后一个节点,慢指针指向倒数第k
个,快慢之间差一个 k 步public class Solution {
public ListNode FindKthToTail(ListNode head,int k) {
if (head == null || k < 0) return null;
ListNode slow = head, fast = head;
// 快指针先走k步
for (int i = 0;i < k;i ++) {
// 时刻判断快指针是否超出链表长度
if (fast == null) return null;
fast = fast.next;
}
while (fast != null) {
slow = slow.next;
fast = fast.next;
}
return slow;
}
}
题目描述: 输入一个链表,反转链表后,输出新链表的表头。
head -> ReverseList(head.next)
,然后我们要做的工作就转换为反转这仅有的两个节点public class Solution {
public ListNode ReverseList(ListNode head) {
if (head == null || head.next == null) return head;
ListNode next = ReverseList(head.next);
head.next.next = head;
head.next = null;
return next;
}
}
public class Solution {
public ListNode ReverseList(ListNode head) {
// 使用迭代
ListNode prev = null;
ListNode curr = head;
while (curr != null) {
ListNode next = curr.next;
curr.next = prev;
prev = curr;
curr = next;
}
// 因为循环跳出的判断就是 curr == null
return prev;
}
}
题目描述: 输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。
public class Solution {
// 使用递归。
public ListNode Merge(ListNode list1,ListNode list2) {
if (list1 == null) {
return list2;
} else if (list2 == null) {
return list1;
} else if (list1.val <= list2.val) {
list1.next = Merge(list1.next, list2);
return list1;
} else {
list2.next = Merge(list1, list2.next);
return list2;
}
}
}
public class Solution {
// 使用双指针,归并
public ListNode Merge(ListNode list1,ListNode list2) {
ListNode dummy = new ListNode(-1);
ListNode prev = dummy;
while (list1 != null && list2 != null) {
if (list1.val <= list2.val) {
prev.next = list1;
list1 = list1.next;
} else {
prev.next = list2;
list2 = list2.next;
}
prev = prev.next;
}
// 出来说明至少有一个链表为空
// l1 为空接上l2,l2为空接上l1
prev.next = list1 == null ? list2 : list1;
return dummy.next;
}
}
题目描述: 输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)
要查找树 A 中是否存在和树 B 结构一样的子树,我们可以分为两步:
public class Solution {
public boolean HasSubtree(TreeNode root1,TreeNode root2) {
if (root1 == null || root2 == null) return false;
boolean res = false;
if (root1.val == root2.val) { // 有相同的根节点,再进行第二步
res = doesTree1HasTree2(root1, root2);
}
if (!res) // 不满足,在左子树中继续查找
res = HasSubtree(root1.left, root2);
if (!res) // 不满足,在右子树中继续查找
res = HasSubtree(root1.right, root2);
return res;
}
// 判断树A中以R为根结点的子树是不是包含和树B一样的结构。
private boolean doesTree1HasTree2(TreeNode r1, TreeNode r2) {
// 对于r2的判断要在r1之前,r2不为空r1为空返回false
// r2为空返回true
if (r2 == null) return true;
if (r1 == null) return false;
if (r1.val != r2.val) return false;
return doesTree1HasTree2(r1.left, r2.left) && doesTree1HasTree2(r1.right, r2.right);
}
}
// 简洁版本,思路相同
class Solution {
public boolean isSubStructure(TreeNode A, TreeNode B) {
if (A == null || B == null) return false;
// 只要在任何地方能够找到满足条件的子结构就行
return dfs(A, B) || isSubStructure(A.left, B)
|| isSubStructure(A.right, B);
}
private boolean dfs(TreeNode A, TreeNode B) {
if (B == null) return true;
if (A == null) return false;
return A.val == B.val && dfs(A.left, B.left) && dfs(A.right, B.right);
}
}
描述见题目链接
求一棵树的镜像的过程:先前序遍历这棵树的每个结点,如果遍历到的结点有子结点,就交换它的两个子结点。当交换完所有的非叶结点的左、右子结点后,就可以得到该树的镜像。
public class Solution {
public void Mirror(TreeNode root) {
if (root != null) {
// 只要有一个孩子节点不为空就可以进行交换
if (root.left != null || root.right != null) {
// 交换左右孩子节点
TreeNode tmp = root.left;
root.left = root.right;
root.right = tmp;
// 以左孩子节点为根节点再做交换
Mirror(root.left);
// 以右孩子节点为根节点再做交换
Mirror(root.right);
}
}
}
}
描述见题目链接
public class Solution {
ArrayList<Integer> res;
public ArrayList<Integer> printMatrix(int [][] matrix) {
res = new ArrayList<>();
if (matrix == null) return null;
// n : row ,m : col
int n = matrix.length, m = matrix[0].length;
int left = 0, right = m - 1;
int up = 0, down = n - 1;
while (left <= right && up <= down) {
// 向右走
for (int j = left;j <= right;j ++)
res.add(matrix[up][j]);
// 向下走
for (int i = up + 1;i <= down;i ++)
res.add(matrix[i][right]);
// 避免只有一行的情况出现:只有一行就不从右往左了,避免重复
if (up < down) {
for (int j = right - 1;j >= left;j --)
res.add(matrix[down][j]);
}
// 避免只有一列的情况出现:只有一列就不从下往上了,避免重复
if (left < right) {
for (int i = down - 1;i > up;i --)
res.add(matrix[i][left]);
}
left ++; right --; up ++; down --;
}
return res;
}
}
题目描述: 定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的 min函数(时间复杂度应为O(1) )。
注意:保证测试中不会当栈为空的时候,对栈调用
pop()
或者min()
或者top()
方法。
public class Solution {
Stack<Integer> stack1 = new Stack<>(); // 存数据
Stack<Integer> stack2 = new Stack<>(); // 存最小值
public void push(int node) {
stack1.push(node);
// 如果stack2为空,此时的最小值就是刚push进来的值
if (stack2.isEmpty())
stack2.push(node);
// 否则,要是刚进来的这个值小于min(),则将刚进来的值push进stack2
else if (node <= this.min())
stack2.push(node);
}
public void pop() {
// 避免栈空
if (stack1.isEmpty()) throw new RuntimeException("栈为空");
int top = stack1.peek();
// 如果出栈的是当前最小值
if (top == this.min())
stack2.pop();
stack1.pop();
}
public int top() {
if (stack1.isEmpty()) throw new RuntimeException("栈为空");
return stack1.peek();
}
public int min() {
if (stack2.isEmpty()) throw new RuntimeException("栈为空");
return stack2.peek();
}
}