Leetcode hot 100题目 easy部分 代码
1. 两数之和
暴力解法,通过两层放循环,实现查找。
20. 有效的括号
这道题的思路大概是 创建一个堆栈 用来保存匹配的左括号,一个hashMap ,map的的键值保成为左括号,map的值保存为右括号。 然后遍历 给定的字符串,当前元素如果是左括号,直接入栈。如果是右括号或?看该右括号是否能和遍历到中的字符匹配。首先将堆栈的最后一个元素出栈(左括号),获取该元素在map中对应的值(右括号),如果不等于当前遍历到的字符,返回错误。
最后只会剩余一个 '?',如果最后堆栈的大小为1,返回true
边界判断:如果stack是空,stack.pop()会有异常。所以在map中加入一对?的键值。
查看代码
class Solution {
private static final Map<Character,Character> map = new HashMap<Character,Character>(){{
put('{','}'); put('[',']'); put('(',')'); put('?','?');
}};
public boolean isValid(String s) {
if(s.length() > 0 && !map.containsKey(s.charAt(0))) return false;
LinkedList<Character> stack = new LinkedList<Character>() {{ add('?'); }};
for(Character c : s.toCharArray()){
if(map.containsKey(c)) stack.addLast(c);
else if(map.get(stack.removeLast()) != c) return false;
}
return stack.size() == 1;
}
}
作者:jyd
链接:https://leetcode-cn.com/problems/valid-parentheses/solution/valid-parentheses-fu-zhu-zhan-fa-by-jin407891080/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
同上
class Solution {
public boolean isValid(String s) {
//利用hashmap,堆栈,进行匹配,左括号入栈,否则出栈并和字符串元素对比
Stack stack = new Stack();
Map map = new HashMap(){{put('{','}');put('(',')');put('[',']');put('?','?');}};
stack.push('?');//考虑栈边界
for(Character c : s.toCharArray()){
if(map.containsKey(c)){
stack.push(c);
}else if(!c.equals(map.get(stack.pop()))){
return false;
}
}
return stack.size() == 1;
}
}
21. 合并两个有序链表
使用递归实现,如果L2的第一个元素小,将L2的next指针指向递归,如果L1的元素小较小,继续递归。
查看代码
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
if (l1 == null) {
return l2;
}
else if (l2 == null) {
return l1;
}
else if (l1.val < l2.val) {
l1.next = mergeTwoLists(l1.next, l2);
return l1;
}
else {
l2.next = mergeTwoLists(l1, l2.next);
return l2;
}
}
}
作者:z1m
链接:https://leetcode-cn.com/problems/merge-two-sorted-lists/solution/yi-kan-jiu-hui-yi-xie-jiu-fei-xiang-jie-di-gui-by-/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
双指针迭代
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode dum = new ListNode(0), cur = dum;
while(l1 != null && l2 != null) {
if(l1.val < l2.val) {
cur.next = l1;
l1 = l1.next;
}
else {
cur.next = l2;
l2 = l2.next;
}
cur = cur.next;
}
cur.next = l1 != null ? l1 : l2;
return dum.next;
}
}
作者:jyd
链接:https://leetcode.cn/problems/he-bing-liang-ge-pai-xu-de-lian-biao-lcof/solution/mian-shi-ti-25-he-bing-liang-ge-pai-xu-de-lian-b-2/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
53. 最大子数组和
使用贪心算法,时间复杂度o(n),空间复杂度o(1)。
定义一个最小和sum,一个max记录每次数组边化之后的和,两个指针left和right。
零下标开始,从左到右 开始记录max的值。将右指针元素加入到max中,再比较相加之后的max和右指针元素,如果相加之后的max值更小,则要将max去掉左指针的元素,左指针开始右移,直到移动到右指针处。得到最大值之后,最大值和之前求得的sum进行比较取较大的。完成一次比较后将右指针右移。
查看代码
class Solution {
public int maxSubArray(int[] nums) {
int left = 0,right = 0;
int max = 0;
int sum = Integer.MIN_VALUE;
while(right < nums.length){
max += nums[right];
while(max - nums[right] < 0 && left <= right){
max -= nums[left];
left ++;
}
sum = Math.max(max,sum);
right ++;
}
return sum;
}
}
作者:xjszsd
链接:https://leetcode-cn.com/problems/maximum-subarray/solution/by-gu-shi-zhong-you-jie-9r24/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
动态规划解法:
讲解看LeetCode,讲解非常清晰。
动态规划未优化
public class Solution {
public int maxSubArray(int[] nums) {
int pre = 0;
int res = nums[0];
for (int num : nums) {
pre = Math.max(pre + num, num);
res = Math.max(res, pre);
}
return res;
}
}
作者:liweiwei1419
链接:https://leetcode.cn/problems/maximum-subarray/solution/dong-tai-gui-hua-fen-zhi-fa-python-dai-ma-java-dai/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
动态规划优化版本
from typing import List
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
size = len(nums)
pre = 0
res = nums[0]
for i in range(size):
pre = max(nums[i], pre + nums[i])
res = max(res, pre)
return res
作者:liweiwei1419
链接:https://leetcode.cn/problems/maximum-subarray/solution/dong-tai-gui-hua-fen-zhi-fa-python-dai-ma-java-dai/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
70. 爬楼梯
1,使用普通递归方法。(答案超时)
2,进一步化简,可以使用记忆化递归方法,即用数组记录第n阶台阶的值。
3,动态规划,记录n个状态,从1到n依次更新
4,斐波那契数列
5,用现代知识
普通递归(超时)
class Solution {
public int climbStairs(int n) {
if(n == 1){
return 1;
}
if( n == 2 ) return 2;
return climbStairs(n - 1) + climbStairs(n -2);
}
}
以上方法会重复递归。
使用记忆化递归,用一个memo数组存储递归过的结果。时间空间复杂度可以到O(n)
记忆化的递归
class Solution {
public int climbStairs(int n) {
int memo[] = new int[n + 1];
return climbStairsMemo(n,memo);
}
//构造数组
public int climbStairsMemo(int n,int memo[]){
if(memo[n] > 0) return memo[n];
if(n == 1){
memo[n] = 1;
}else if(n == 2){
memo[n] = 2;
}else{
memo[n] = climbStairsMemo(n-1,memo) + climbStairsMemo(n-2,memo);
}
return memo[n];
}
}
94. 二叉树的中序遍历
1,使用递归解法
2,迭代方法,定义一个堆栈
递归做法
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<Integer>();
inorder(root, res);
return res;
}
public void inorder(TreeNode root, List<Integer> res) {
if (root == null) {
return;
}
inorder(root.left, res);
res.add(root.val);
inorder(root.right, res);
}
}
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/binary-tree-inorder-traversal/solution/er-cha-shu-de-zhong-xu-bian-li-by-leetcode-solutio/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
迭代实现
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<Integer>();
Deque<TreeNode> stk = new LinkedList<TreeNode>();
while (root != null || !stk.isEmpty()) {
while (root != null) {
stk.push(root);
root = root.left;
}
root = stk.pop();
res.add(root.val);
root = root.right;
}
return res;
}
}
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/binary-tree-inorder-traversal/solution/er-cha-shu-de-zhong-xu-bian-li-by-leetcode-solutio/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
101. 对称二叉树
递归判断,判断A,B两指针节点是否相等,A的右子树与B的左子树是否对称相等,判断A的左子树与B的右子树是否对称相等。
注意递归重点的顺序:先判断左右结点,都为空返回true,然后如果两者中的一个为空,返回false,用`||`符号,最后的情况是两者都不为空的情况。
递归判断对称
class Solution {
public boolean isSymmetric(TreeNode root) {
if(root==null) {
return true;
}
//调用递归函数,比较左节点,右节点
return dfs(root.left,root.right);
}
boolean dfs(TreeNode left, TreeNode right) {
//递归的终止条件是两个节点都为空
//或者两个节点中有一个为空
//或者两个节点的值不相等
if(left==null && right==null) {
return true;
}
if(left==null || right==null) {
return false;
}
if(left.val!=right.val) {
return false;
}
//再递归的比较 左节点的左孩子 和 右节点的右孩子
//以及比较 左节点的右孩子 和 右节点的左孩子
return dfs(left.left,right.right) && dfs(left.right,right.left);
}
}
作者:wang_ni_ma
链接:https://leetcode-cn.com/problems/symmetric-tree/solution/dong-hua-yan-shi-101-dui-cheng-er-cha-shu-by-user7/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
104. 二叉树的最大深度
递归做法。节点为空时说明高度为 0,所以返回 0;节点不为空时则分别求左右子树的高度的最大值,同时加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;
} else {
int left = maxDepth(root.left);
int right = maxDepth(root.right);
return Math.max(left, right) + 1;
}
}
}
作者:guanpengchn
链接:https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/solution/hua-jie-suan-fa-104-er-cha-shu-de-zui-da-shen-du-b/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
121. 买卖股票的最佳时机
暴力解法思路:枚举所有发生一次交易的股价差。
暴力解法(运行超时)
public class Solution {
public int maxProfit(int[] prices) {
int len = prices.length;
if (len < 2) {
return 0;
}
// 有可能不发生交易,因此结果集的初始值设置为 0
int res = 0;
// 枚举所有发生一次交易的股价差
for (int i = 0; i < len - 1; i++) {
for (int j = i + 1; j < len; j++) {
res = Math.max(res, prices[j] - prices[i]);
}
}
return res;
}
}
作者:liweiwei1419
链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/solution/bao-li-mei-ju-dong-tai-gui-hua-chai-fen-si-xiang-b/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
动态规划没咋看懂
public class Solution {
public int maxProfit(int[] prices) {
int len = prices.length;
// 特殊判断
if (len < 2) {
return 0;
}
int[][] dp = new int[len][2];
// dp[i][0] 下标为 i 这天结束的时候,不持股,手上拥有的现金数
// dp[i][1] 下标为 i 这天结束的时候,持股,手上拥有的现金数
// 初始化:不持股显然为 0,持股就需要减去第 1 天(下标为 0)的股价
dp[0][0] = 0;
dp[0][1] = -prices[0];
// 从第 2 天开始遍历
for (int i = 1; i < len; i++) {
dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i]);
dp[i][1] = Math.max(dp[i - 1][1], -prices[i]);
}
return dp[len - 1][0];
}
}
作者:liweiwei1419
链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/solution/bao-li-mei-ju-dong-tai-gui-hua-chai-fen-si-xiang-b/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
一次遍历
public class Solution {
public int maxProfit(int prices[]) {
int minprice = Integer.MAX_VALUE;
int maxprofit = 0;
for (int i = 0; i < prices.length; i++) {
if (prices[i] < minprice) {
minprice = prices[i];
} else if (prices[i] - minprice > maxprofit) {
maxprofit = prices[i] - minprice;
}
}
return maxprofit;
}
}
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/solution/121-mai-mai-gu-piao-de-zui-jia-shi-ji-by-leetcode-/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
使用minprice获得最小股价,使用maxprofit记录最大收益
迭代,当前股价小于最小股价,说明下跌了,更新最小股价。如果当前股价减去最小价格大于最大收益,则更新maxprofit的值。一直迭代得到最大收益。
136. 只出现一次的数字
如果允许使用额外空间,可以使用哈希表或集合。
要求不使用额外的空间,可以使用异或运算符号解决问题:
异或运算符解法代码实现
class Solution {
public int singleNumber(int[] nums) {
int single = 0;
for (int num : nums) {
single ^= num;
}
return single;
}
}
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/single-number/solution/zhi-chu-xian-yi-ci-de-shu-zi-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
141. 环形链表
思路:使用快慢指针,快指针每次走两步,慢指针每次走一步。如果有环,快慢指针会相遇。
快慢指针做法
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public boolean hasCycle(ListNode head) {
//快慢指针
ListNode slow = head,fast = head;
while(slow!=null&&fast.next!=null&&fast.next.next!=null){
//慢指针走一步,快指针走两步
slow = slow.next;
fast = fast.next.next;
//当快慢指针相遇的时候,则链表存在环
if(slow == fast){
return true;
}
}
return false;
}
}
链表问题:https://leetcode-cn.com/problems/linked-list-cycle/solution/yi-wen-gao-ding-chang-jian-de-lian-biao-wen-ti-h-2/
155. 最小栈
使用辅助栈保存当前数据栈中的最小元素。进栈时数据栈直接入栈,如果入栈元素大于辅助栈栈顶元素,再将辅助栈顶元素入辅助栈,如果入栈元素小于辅助栈栈顶元素,将入栈元素入辅助栈。出栈时,两个栈同时出栈。
stack.peek():该方法返回堆栈顶部的元素,如果堆栈为空,则返回NULL
辅助栈解法
import java.util.Stack;
public class MinStack {
// 数据栈
private Stack<Integer> data;
// 辅助栈
private Stack<Integer> helper;
/**
* initialize your data structure here.
*/
public MinStack() {
data = new Stack<>();
helper = new Stack<>();
}
// 思路 1:数据栈和辅助栈在任何时候都同步
public void push(int x) {
// 数据栈和辅助栈一定会增加元素
data.add(x);
if (helper.isEmpty() || helper.peek() >= x) {
helper.add(x);
} else {
helper.add(helper.peek());
}
}
public void pop() {
// 两个栈都得 pop
if (!data.isEmpty()) {
helper.pop();
data.pop();
}
}
public int top() {
if(!data.isEmpty()){
return data.peek();
}
throw new RuntimeException("栈中元素为空,此操作非法");
}
public int getMin() {
if(!helper.isEmpty()){
return helper.peek();
}
throw new RuntimeException("栈中元素为空,此操作非法");
}
}
作者:liweiwei1419
链接:https://leetcode-cn.com/problems/min-stack/solution/shi-yong-fu-zhu-zhan-tong-bu-he-bu-tong-bu-python-/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
160. 相交链表
这题也是计算机综合考试考研题目真题。
双指针思路:
pA走过的路径为A链+B链
pB走过的路径为B链+A链
pA和pB走过的长度都相同,都是A链和B链的长度之和,相当于将两条链从尾端对齐,如果相交,则会提前在相交点相遇,如果没有相交点,则会在最后相遇。
pA:1->2->3->4->5->6->null->9->5->6->null
pB:9->5->6->null->1->2->3->4->5->6->null
也可理解为:
若相交,链表A: a+c, 链表B : b+c ,a+c+b+c = b+c+a+c 则会在公共处c起点相遇。
若不相交,a +b = b+a 。因此相遇处是NULL
双指针题解
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if (headA == null || headB == null) return null;
ListNode pA = headA, pB = headB;
while (pA != pB) {
pA = pA == null ? headB : pA.next;
pB = pB == null ? headA : pB.next;
}
return pA;
}
作者:reals
链接:https://leetcode-cn.com/problems/intersection-of-two-linked-lists/solution/tu-jie-xiang-jiao-lian-biao-by-user7208t/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
169. 多数元素
排序
class Solution {
public int majorityElement(int[] nums) {
Arrays.sort(nums);
return nums[nums.length >> 1];
}
}
摩尔投票法:B站视频讲解
摩尔投票法
class Solution {
public int majorityElement(int[] nums) {
int cand_num = nums[0], count = 1;
for (int i = 1; i < nums.length; ++i) {
if (cand_num == nums[i])
++count;
else if (--count == 0) {
cand_num = nums[i];
count = 1;
}
}
return cand_num;
}
}
作者:gfu
链接:https://leetcode-cn.com/problems/majority-element/solution/3chong-fang-fa-by-gfu-2/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
206. 反转链表
双指针算法:
双指针
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;
}
return prev;
}
}
作者:LeetCode-Solution
链接:https://leetcode.cn/problems/reverse-linked-list/solution/fan-zhuan-lian-biao-by-leetcode-solution-d1k2/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
递归做法:
递归做法: 递归动画演示
查看代码
class Solution {
public ListNode reverseList(ListNode head) {
//递归终止条件是当前为空,或者下一个节点为空
if(head==null || head.next==null) {
return head;
}
//这里的cur就是最后一个节点
ListNode cur = reverseList(head.next);
//这里请配合动画演示理解
//如果链表是 1->2->3->4->5,那么此时的cur就是5
//而head是4,head的下一个是5,下下一个是空
//所以head.next.next 就是5->4
head.next.next = head;
//防止链表循环,需要将head.next设置为空
head.next = null;
//每层递归函数都返回cur,也就是最后一个节点
return cur;
}
}
作者:wang_ni_ma
链接:https://leetcode-cn.com/problems/reverse-linked-list/solution/dong-hua-yan-shi-206-fan-zhuan-lian-biao-by-user74/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
226. 翻转二叉树
递归做法
class Solution {
public TreeNode invertTree(TreeNode root) {
//递归函数的终止条件,节点为空时返回
if(root==null) {
return null;
}
//下面三句是将当前节点的左右子树交换
TreeNode tmp = root.right;
root.right = root.left;
root.left = tmp;
//递归交换当前节点的 左子树
invertTree(root.left);
//递归交换当前节点的 右子树
invertTree(root.right);
//函数返回时就表示当前这个节点,以及它的左右子树
//都已经交换完了
return root;
}
}
作者:wang_ni_ma
链接:https://leetcode-cn.com/problems/invert-binary-tree/solution/dong-hua-yan-shi-liang-chong-shi-xian-226-fan-zhua/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
也可以用层序遍历的方法,利用辅助队列做。
修改 node 会影响root的内存,其中因为最开始 node和 root 都是引用同一个对象的,类似于c++的指针。不直接操作root,是为了防止丢失root指针。
层序遍历
class Solution {
public TreeNode mirrorTree(TreeNode root) {
if(root == null) return null;
Queue<TreeNode> queue = new LinkedList(){{offer(root);}};
while(!queue.isEmpty()){
TreeNode node = queue.poll();
TreeNode tmp = node.left;
node.left = node.right;
node.right = tmp;
if(node.left != null) queue.offer(node.left);
if(node.right != null) queue.offer(node.right);
}
return root;
}
}
作者:wang_ni_ma
链接:https://leetcode-cn.com/problems/invert-binary-tree/solution/dong-hua-yan-shi-liang-chong-shi-xian-226-fan-zhua/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
234. 回文链表
复制到数组中再用双指针:
class Solution {
public boolean isPalindrome(ListNode head) {
List<Integer> vals = new ArrayList<Integer>();
// 将链表的值复制到数组中
ListNode currentNode = head;
while (currentNode != null) {
vals.add(currentNode.val);
currentNode = currentNode.next;
}
// 使用双指针判断是否回文
int front = 0;
int back = vals.size() - 1;
while (front < back) {
if (!vals.get(front).equals(vals.get(back))) {
return false;
}
front++;
back--;
}
return true;
}
}
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/palindrome-linked-list/solution/hui-wen-lian-biao-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
快慢指针做法:整个流程可以分为以下五个步骤:
找到前半部分链表的尾节点。
反转后半部分链表。
判断是否回文。
恢复链表。
返回结果
class Solution {
public boolean isPalindrome(ListNode head) {
if (head == null) {
return true;
}
// 找到前半部分链表的尾节点并反转后半部分链表
ListNode firstHalfEnd = endOfFirstHalf(head);
ListNode secondHalfStart = reverseList(firstHalfEnd.next);
// 判断是否回文
ListNode p1 = head;
ListNode p2 = secondHalfStart;
boolean result = true;
while (result && p2 != null) {
if (p1.val != p2.val) {
result = false;
}
p1 = p1.next;
p2 = p2.next;
}
// 还原链表并返回结果
firstHalfEnd.next = reverseList(secondHalfStart);
return result;
}
private ListNode reverseList(ListNode head) {
ListNode prev = null;
ListNode curr = head;
while (curr != null) {
ListNode nextTemp = curr.next;
curr.next = prev;
prev = curr;
curr = nextTemp;
}
return prev;
}
private ListNode endOfFirstHalf(ListNode head) {
ListNode fast = head;
ListNode slow = head;
while (fast.next != null && fast.next.next != null) {
fast = fast.next.next;
slow = slow.next;
}
return slow;
}
}
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/palindrome-linked-list/solution/hui-wen-lian-biao-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
338. 比特位计数
Brian Kernighan 算法的原理:对于任意整数 x,令 x=x & (x−1),该运算将 x 的二进制表示的最后一个 1 变成 0。因此,对 x 重复该操作,直到 x 变成 0,则操作次数即为 x 的「一比特数」。
例如:5的二进制表示是101,操作两次101 & 100 -》100 & 011-》0
用brian kernighan 算法
class Solution {
public int[] countBits(int n) {
int[] bits = new int[n + 1];
for (int i = 0; i <= n; i++) {
bits[i] = countOnes(i);
}
return bits;
}
public int countOnes(int x) {
int ones = 0;
while (x > 0) {
x &= (x - 1);
ones++;
}
return ones;
}
}
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/counting-bits/solution/bi-te-wei-ji-shu-by-leetcode-solution-0t1i/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
还有更巧妙的做法:
二进制表示中,奇数一定比前面那个偶数多一个 1。偶数中 1 的个数一定和除以 2 之后的那个数一样多。
奇数举例: 0 = 0 1 = 1
2 = 10 3 = 11
偶数举例:
2 = 10 4 = 100 8 = 1000
3 = 11 6 = 110 12 = 1100
查看代码
vector<int> countBits(int num) {
vector<int> result(num+1);
result[0] = 0;
for(int i = 1; i <= num; i++)
{
if(i % 2 == 1)
{
result[i] = result[i-1] + 1;
}
else
{
result[i] = result[i/2];
}
}
return result;
}
作者:duadua
链接:https://leetcode-cn.com/problems/counting-bits/solution/hen-qing-xi-de-si-lu-by-duadua/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
283. 移动零
思路:创建两个指针i和j,第一次遍历的时候,i从0下标开始遍历到数组末尾,每遇到一个非0元素就将i下标所在元素赋值给指针j所在下标,第一次遍历完后,j指针的下标就指向了最后一个非0元素下标。第二次遍历的时候,起始位置就从j开始到结束,将剩下的这段区域内的元素全部置为0。
两次遍历
class Solution {
public void moveZeroes(int[] nums) {
if(nums==null) {
return;
}
//第一次遍历的时候,j指针记录非0的个数,只要是非0的统统都赋给nums[j]
int j = 0;
for(int i=0;i<nums.length;++i) {
if(nums[i]!=0) {
nums[j++] = nums[i];
}
}
//非0元素统计完了,剩下的都是0了
//所以第二次遍历把末尾的元素都赋为0即可
for(int i=j;i<nums.length;++i) {
nums[i] = 0;
}
}
}
作者:wang_ni_ma
链接:https://leetcode-cn.com/problems/move-zeroes/solution/dong-hua-yan-shi-283yi-dong-ling-by-wang_ni_ma/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
448. 找到所有数组中消失的数字
原地哈希:
从0下标开始遍历,如果下标所在元素等于下标+1,说明这个元素在它的位置,索引自增遍历就行。如果不等,先求出当前元素的目标索引targetIndex:元素值-1,如果目标索引的元素值等于当前索引的值,说明元素重复,索引自增,并跳过此次循环。如果不重复,交换两个元素。
最后遍历数组,如果元素值不等于索引+1,说明 索引+1 缺失。
原地哈希
class Solution {
public List<Integer> findDisappearedNumbers(int[] nums) {
int len = nums.length;
int index = 0;
while(index < len){
if(nums[index] == index + 1){
index++;
}else{
int targetIndex = nums[index] - 1;
if(nums[targetIndex] == nums[index]){
index++;
continue;
}
int temp = nums[targetIndex];
nums[targetIndex] = nums[index];
nums[index] = temp;
}
}
List<Integer> res = new ArrayList<>();
for(int i = 0; i < len; i++){
if(nums[i] != i + 1)
res.add(i + 1);
}
return res;
}
}
作者:venturekwok
链接:https://leetcode-cn.com/problems/find-all-numbers-disappeared-in-an-array/solution/java-yuan-di-ha-xi-si-lu-qing-xi-dai-ma-a12yd/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
461. 汉明距离
在工程中,我们应该直接使用内置函数
直接调用函数
class Solution {
public int hammingDistance(int x, int y) {
return Integer.bitCount(x ^ y);
}
}
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/hamming-distance/solution/yi-ming-ju-chi-by-leetcode-solution-u1w7/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
也可以自己手动检测1的位数
查看代码
//如果最低位为 1,那么令计数器加一,然后我们令 s 整体右移一位。这样 s 的最低位将被舍去,原本的次低位就变成了新的最低位。
//我们重复这个过程直到 s=0 为止。
class Solution {
public int hammingDistance(int x, int y) {
int s = x ^ y, ret = 0;
while (s != 0) {
ret += s & 1;
s >>= 1;
}
return ret;
}
}
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/hamming-distance/solution/yi-ming-ju-chi-by-leetcode-solution-u1w7/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
543. 二叉树的直径
思路:根节点可能不在直径上面,任意节点开始计算。重点是任意一个结点,都要记录以此结点为根的直径情况:左子树高度+右子树高度
预防踩坑:leetcode
查看代码
class Solution {
private int ans;//需要一个值来保存每次比较更新的最大直径值
public int diameterOfBinaryTree(TreeNode root) {
if(root == null){
return -1;
}
maxDepth(root);
return ans;
}
private int maxDepth(TreeNode root) {
if(root == null){
return 0;
}
int left = maxDepth(root.left);
int right = maxDepth(root.right);
ans = Math.max(ans, left + right);
return Math.max(left, right) + 1;
}
}
617. 合并二叉树
递归实现合并,如果两个二叉树中的的某个二叉树节点为空,返回不为空的节点。将第二个二叉树节点合并到第一个二叉树节点上面。最后返回第一颗二叉树。
递归实现
class Solution {
public TreeNode mergeTrees(TreeNode t1, TreeNode t2) {
if(t1==null || t2==null) {
return t1==null? t2 : t1;
}
return dfs(t1,t2);
}
TreeNode dfs(TreeNode r1, TreeNode r2) {
// 如果 r1和r2中,只要有一个是null,函数就直接返回
if(r1==null || r2==null) {
return r1==null? r2 : r1;
}
//让r1的值 等于 r1和r2的值累加,再递归的计算两颗树的左节点、右节点
r1.val += r2.val;
r1.left = dfs(r1.left,r2.left);
r1.right = dfs(r1.right,r2.right);
return r1;
}
}
作者:wang_ni_ma
链接:https://leetcode-cn.com/problems/merge-two-binary-trees/solution/dong-hua-yan-shi-di-gui-die-dai-617he-bing-er-cha-/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
posted on 2022-05-07 21:47 passionConstant 阅读(25) 评论(0) 编辑 收藏 举报