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编辑  收藏  举报