赞
踩
目录
Leetcode-104. maximum-depth-of-binary-tree
Given a linked list, determine if it has a cycle in it.
To represent a cycle in the given linked list, we use an integer pos which represents the position (0-indexed) in the linked list where tail connects to. If pos is -1, then there is no cycle in the linked list.
给定一个链表,判断链表中是否有环。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
方法一:
首先创建一个以节点 ID 为键的 HashMap 集合,用来存储曾经遍历过的节点。然后同样是从头节点开始,依次遍历单链表的每一个节点。每遍历到一个新节点,就用新节点和 HashMap 集合当中存储的节点作比较,如果发现 HashMap 当中存在相同节点ID,则说明链表有环,如果 HashMap 当中不存在相同的节点 ID,就把这个新节点 ID 存入 HashMap,之后进入下一节点,继续重复刚才的操作。
这个方法在流程上和方法一类似,本质的区别是使用了 HashMap 作为额外的缓存。
假设从链表头节点到入环点的距离是 D,链表的环长是 S。而每一次 HashMap 查找元素的时间复杂度是 O(1), 所以总体的时间复杂度是 1*(D+S)=D+S,可以简单理解为 O(N)。而算法的空间复杂度还是 D+S-1,可以简单地理解成 O(N)。
- import java.util.*;
- public class Solution {
-
- public boolean hasCycle(ListNode head) {
- Set<ListNode> set = new HashSet<>();
- while(head != null) {
- if(set.contains(head)) {
- return true;
- }
- set.add(head);
- head = head.next;
- }
- return false;
- }
- }
方法二:
首先创建两个指针1和2(在 java 里就是两个对象引用),同时指向这个链表的头节点。然后开始一个大循环,在循环体中,让指针1每次向下移动一个节点,让指针2每次向下移动两个节点,然后比较两个指针指向的节点是否相同。如果相同,则判断出链表有环,如果不同,则继续下一次循环。
例如链表 A->B->C->D->B->C->D,两个指针最初都指向节点 A,进入第一轮循环,指针1移动到了节点 B,指针2移动到了 C。第二轮循环,指针1移动到了节点 C,指针2移动到了节点 B。第三轮循环,指针1移动到了节点 D,指针2移动到了节点 D,此时两指针指向同一节点,判断出链表有环。
此方法也可以用一个更生动的例子来形容:在一个环形跑道上,两个运动员在同一地点起跑,一个运动员速度快,一个运动员速度慢。当两人跑了一段时间,速度快的运动员必然会从速度慢的运动员身后再次追上并超过,原因很简单,因为跑道是环形的。
- import java.util.*;
- public class Solution {
-
- public boolean hasCycle(ListNode head) {
- if(head == null) {
- return false;
- }
- ListNode fast = head.next;
- ListNode slow = head;
- while(fast != slow) {
- if(fast == null || fast.next == null) {
- return false;
- }
-
- fast = fast.next.next;
- slow = slow.next;
- }
- return true;
- }
- }
给你一个链表,删除链表的倒数第 n
个结点,并且返回链表的头结点。
- public ListNode removeNthFromEnd (ListNode head, int n) {
- if(head == null || n < 0) {
- return null;
- }
- ListNode temp = new ListNode(0);
- temp.next = head;
- ListNode fast = temp;
- ListNode slow = temp;
- for(int i = 0; i <= n; i ++) {
- if(fast == null) {
- return temp.next;
- }
- fast = fast.next;
- }
- while(fast != null) {
- fast = fast.next;
- slow = slow.next;
- }
- slow.next = slow.next.next;
-
- return temp.next;
- }
请判断一个链表是否为回文链表。
- public boolean isPalindrome(ListNode head) {
- StringBuilder StringBuilder = new StringBuilder();
- List<Integer> list = new ArrayList<>();
- while(head != null) {
- list.add(head.val);
- StringBuilder.append(head.val);
- head = head.next;
- }
-
- StringBuilder revesStringBuilder = new StringBuilder();
- for(int i = list.size() - 1; i >= 0; i --) {
- revesStringBuilder.append(list.get(i));
- }
-
- if(StringBuilder.toString().equals(revesStringBuilder.toString())) {
- return true;
- }
-
- return false;
- }
反转一个单链表。
示例:
- 输入: 1->2->3->4->5->NULL
- 输出: 5->4->3->2->1->NULL
- public ListNode reverseList(ListNode head) {
- if(head == null) {
- return null;
- }
-
- ListNode preNode = null;
- ListNode nextNode = null;
- while(head != null) {
- nextNode = head.next;
- head.next = preNode;
-
- preNode = head;
- head = nextNode;
- }
- return preNode;
- }
编写一个程序,找到两个单链表相交的起始节点。
输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Reference of the node with value = 8
输入解释:相交节点的值为 8 (注意,如果两个链表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。
- public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
- int lengthA = getLength(headA);
- int lengthB = getLength(headB);
-
- ListNode a = headA;
- ListNode b = headB;
-
- if(lengthA > lengthB) {
- for(int i = 0; i < lengthA - lengthB; i ++) {
- a = a.next;
- }
- } else {
- for(int j = 0; j < lengthB - lengthA; j ++) {
- b = b.next;
- }
- }
-
- while(a != b) {
- a = a.next;
- b = b.next;
- }
- return a;
- }
-
- public int getLength(ListNode head){
- int length = 0;
- while(head != null) {
- length ++;
- head = head.next;
- }
- return length;
- }
实现一种算法,找出单向链表中倒数第 k 个节点。返回该节点的值。
注意:本题相对原题稍作改动
示例:
输入: 1->2->3->4->5 和 k = 2
输出: 4
- public int kthToLast(ListNode head, int k) {
- if (head == null || k < 0) {
- return 0;
- }
- ListNode fast = head;
- ListNode slow = head;
- for (int i = 0; i < k; i ++) {
- fast = fast.next;
- }
-
- while (fast != null) {
- fast = fast.next;
- slow = slow.next;
- }
-
- return slow.val;
-
- }
将两个升序链表合并为一个新的升序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
- public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
- ListNode head = new ListNode(-1);
- ListNode current = head;
- while(l1 != null && l2 != null) {
- if(l1.val > l2.val) {
- current.next = l2;
- l2 = l2.next;
- } else {
- current.next = l1;
- l1 = l1.next;
- }
- current = current.next;
- }
-
- if(l1 != null) {
- current.next = l1;
- }
-
- if(l2 != null) {
- current.next = l2;
- }
-
- return head.next;
-
- }
给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。
示例 1:
输入: 1->1->2
输出: 1->2
示例 2:
输入: 1->1->2->3->3
输出: 1->2->3
- public ListNode deleteDuplicates(ListNode head) {
- if(head == null) {
- return null;
- }
-
- ListNode current = head;
- while(current != null && current.next != null) {
- if(current.val == current.next.val) {
- current.next = current.next.next;
- } else {
- current = current.next;
- }
- }
- return head;
- }
输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。
示例 1:
- 输入:head = [1,3,2]
- 输出:[2,3,1]
- public int[] reversePrint(ListNode head) {
- if(head == null) {
- return new int[0];
- }
-
- Stack<Integer> stack = new Stack<>();
- while(head != null) {
- stack.push(head.val);
- head = head.next;
- }
-
- List<Integer> list = new ArrayList<>();
- while(!stack.empty()) {
- list.add(stack.pop());
- }
- int [] arrays = new int[list.size()];
- for(int i = 0; i < list.size(); i ++) {
- arrays[i] = list.get(i);
- }
- return arrays;
- }
给定一个头结点为 head
的非空单链表,返回链表的中间结点。
如果有两个中间结点,则返回第二个中间结点。
- public ListNode middleNode(ListNode head) {
- if(head == null) {
- return null;
- }
- ListNode fast = head;
- ListNode slow = head;
- while (fast != null && fast.next != null) {
- fast = fast.next.next;
- slow = slow.next;
- }
- return slow;
- }
Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000.
给定一个字符串 s
,找到 s
中最长的回文子串。你可以假设 s
的最大长度为 1000。
事实上,只需使用恒定的空间,我们就可以在 O(n^2)O(n2) 的时间内解决这个问题。
我们观察到回文中心的两侧互为镜像。因此,回文可以从它的中心展开,并且只有 2n−1 个这样的中心。
你可能会问,为什么会是 2n−1 个,而不是 n 个中心?原因在于所含字母数为偶数的回文的中心可以处于两字母之间(例如 \textrm{“abba”}“abba” 的中心在两个 \textrm{‘b’}‘b’ 之间)。
- class Solution {
- public String longestPalindrome(String s) {
- if (s == null || s.length() < 1) return "";
- int start = 0, end = 0;
- for (int i = 0; i < s.length(); i++) {
- int len1 = expandAroundCenter(s, i, i);
- int len2 = expandAroundCenter(s, i, i + 1);
- int len = Math.max(len1, len2);
- if (len > end - start) {
- start = i - (len - 1) / 2;
- end = i + len / 2;
- }
- }
- return s.substring(start, end + 1);
- }
-
- private int expandAroundCenter(String s, int left, int right) {
- int L = left, R = right;
- while (L >= 0 && R < s.length() && s.charAt(L) == s.charAt(R)) {
- L--;
- R++;
- }
- return R - L - 1;
- }
-
- }
Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: get and put.
get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.
put(key, value) - Set or insert the value if the key is not already present. When the cache reached its capacity, it should invalidate the least recently used item before inserting a new item.
The cache is initialized with a positive capacity.
Follow up:
Could you do both operations in O(1) time complexity?
Example:
LRUCache cache = new LRUCache( 2 /* capacity */ );
cache.put(1, 1);
cache.put(2, 2);
cache.get(1); // returns 1
cache.put(3, 3); // evicts key 2
cache.get(2); // returns -1 (not found)
cache.put(4, 4); // evicts key 1
cache.get(1); // returns -1 (not found)
cache.get(3); // returns 3
cache.get(4); // returns 4
- class LRUCache {
- private LinkedHashMap<Integer, Integer> map;
- private final int cacheSize;
- public LRUCache(int capacity) {
- cacheSize = capacity;
- map = new LinkedHashMap<Integer, Integer>(capacity, 0.75f, true) {
- protected boolean removeEldestEntry(Map.Entry eldest) {
- return size() > cacheSize;
- }
- };
- }
-
- public int get(int key) {
- return map.getOrDefault(key, -1);
- }
-
- public void put(int key, int value) {
- map.put(key, value);
- }
- }
-
- /**
- * Your LRUCache object will be instantiated and called as such:
- * LRUCache obj = new LRUCache(capacity);
- * int param_1 = obj.get(key);
- * obj.put(key,value);
- */
编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。
不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。
你可以假设数组中的所有字符都是 ASCII 码表中的可打印字符。
示例 1:
输入:["h","e","l","l","o"]
输出:["o","l","l","e","h"]
示例 2:
输入:["H","a","n","n","a","h"]
输出:["h","a","n","n","a","H"]
- public void reverseString(char[] s) {
- if(s == null || s.length == 0) {
- return;
- }
-
- for(int i = 0; i < s.length/2; i ++) {
- char temp = s[i];
- s[i] = s[s.length - i - 1];
- s[s.length - i - 1] = temp;
- }
-
- }
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
- public int lengthOfLongestSubstring(String s) {
- Set<Character> set = new HashSet<>();
- int length = s.length();
- int rk = -1, ans = 0;
- for (int i = 0; i < length; i ++) {
- if (i != 0) {
- set.remove(s.charAt(i - 1));
- }
-
- while (rk + 1 < length && !set.contains(s.charAt(rk + 1))) {
- set.add(s.charAt(rk + 1));
- rk ++;
- }
- ans = Math.max(ans, rk - i + 1);
- }
- return ans;
- }
Given an integer array nums, find the contiguous subarray (containing at least one number) which has the largest sum and return its sum.
Example:
Input: [-2,1,-3,4,-1,2,1,-5,4],
Output: 6
Explanation: [4,-1,2,1] has the largest sum = 6.
Follow up:
If you have figured out the O(n) solution, try coding another solution using the divide and conquer approach, which is more subtle.
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例:
输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
进阶:
如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。
代码实现:
- class Solution {
- public int maxSubArray(int[] nums) {
- int ans = nums[0];
- int sum = 0;
- for(int num:nums) {
- if(sum > 0) {
- sum = sum + num;
- } else {
- sum = num;
- }
- ans = (sum > ans)?sum:ans;
- }
- return ans;
- }
- }
一 题目描述
Given a non-empty array of integers, every element appears twice except for one. Find that single one.
Note:
Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?
现在有一个整数类型的数组,数组中素只有一个元素只出现一次,其余的元素都出现两次。
注意:
你需要给出一个线性时间复杂度的算法,你能在不使用额外内存空间的情况下解决这个问题么?
二 题目分析
2.1 异或规则
该题目可以考虑使用异或,异或规则:
A:0 XOR n = n
B:n XOR n = 0
2.2 举例说明
假设数组为 2,3,2,3,4,5,4
那么结果应该为1
2^3=0000 0010 ^ 0000 0011 = 0000 0001 1
1^2=0000 0001 ^ 0000 0010 = 0000 0011 3
3^3=0000 0011 ^ 0000 0011 = 0000 0000 0
0^4=0000 0000 ^ 0000 0100 = 0000 0100 4
4^5=0000 0100 ^ 0000 0101 = 0000 0101 1
1^4=0000 0001 ^ 0000 0100 = 0000 0101 5
整个过程如上,最后结果为5
三 题目解答
- public class Solution {
- public int singleNumber(int[] A) {
- int result = 0;
- for(int i=0; i< A.length; i++) {
- result ^= A[i];
- }
- return result;
- }
- }
一 题目描述
求给定二叉树的最大深度,
最大深度是指树的根结点到最远叶子结点的最长路径上结点的数量。
Given a binary tree, find its maximum depth.
The maximum depth is the number of nodes along the longest path from the root node down to the farthest leaf node.
二 题目求解
2.1 递归解法
- /**
- * Definition for binary tree
- * public class TreeNode {
- * int val;
- * TreeNode left;
- * TreeNode right;
- * TreeNode(int x) { val = x; }
- * }
- */
- public class Solution {
- public int maxDepth(TreeNode root) {
- if(root == null) return 0;
- int lDepth = maxDepth(root.left);
- int rDepth = maxDepth(root.right);
- return 1+(lDepth>rDepth?lDepth:rDepth);
- }
- }
2.2 使用 queue 进行层序遍历
- public int maxDepth(TreeNode root) {
- if (root == null)
- return 0;
- Queue<TreeNode> queue = new LinkedList<TreeNode>();
- int res = 0;
- queue.add(root);
- while (!queue.isEmpty()) {
- int size = queue.size();
- for (int i = 0; i < size; i++) {
- TreeNode node = queue.poll();
- if (node.left != null)
- queue.add(node.left);
- if (node.right != null)
- queue.add(node.right);
- }
- res++;
- }
-
- return res;
- }
给定一个包含 n + 1 个整数的数组 nums ,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数。
假设 nums 只有 一个重复的整数 ,找出 这个重复的数 。
- public int findDuplicate(int[] nums) {
- if(nums == null || nums.length == 0) {
- return 0;
- }
-
- Set<Integer> set = new HashSet<>();
- for(int num : nums) {
- if(set.contains(num)) {
- return num;
- }
- set.add(num);
- }
- return -1;
- }
给定一个排序数组,你需要在 原地 删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。
不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
示例 1:
给定数组 nums = [1,1,2],
函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。
你不需要考虑数组中超出新长度后面的元素。
示例 2:
给定 nums = [0,0,1,1,1,2,2,3,3,4],
函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。
你不需要考虑数组中超出新长度后面的元素。
- public int removeDuplicates(int[] nums) {
- if(nums == null || nums.length == 0) {
- return 0;
- }
-
- int k = 0;
- int p = nums[0];
- for(int i = 1; i < nums.length; i++) {
- if(nums[i] != nums[k]) {
- k++;
- nums[k] = nums[i];
- }
- }
- return k + 1;
- }
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
示例 1:
输入: nums = [-1,0,3,5,9,12], target = 9
输出: 4
解释: 9 出现在 nums 中并且下标为 4
- public int search(int[] nums, int target) {
- if(nums == null || nums.length < 0) {
- return -1;
- }
-
- int left = 0;
- int right = nums.length - 1;
- while(left <= right) {
- int point = (left + right)/2;
- if(nums[point] == target) {
- return point;
- }
-
- if(nums[point] < target) {
- left = point + 1;
- }
-
- if(nums[point] > target) {
- right = point - 1;
- }
- }
- return -1;
- }
给定一个包含 n + 1 个整数的数组 nums ,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数。
假设 nums 只有 一个重复的整数 ,找出 这个重复的数 。
示例 1:
输入:nums = [1,3,4,2,2]
输出:2
示例 2:
输入:nums = [3,1,3,4,2]
输出:3
- public int findDuplicate(int[] nums) {
- if(nums == null || nums.length == 0) {
- return 0;
- }
-
- Set<Integer> set = new HashSet<>();
- for(int num : nums) {
- if(set.contains(num)) {
- return num;
- }
- set.add(num);
- }
- return -1;
- }
给你二叉树的根节点 root
,返回它节点值的 前序 遍历。
输入:root = [1,null,2,3]
输出:[1,2,3]
示例 2:
输入:root = []
输出:[]
示例 3:
输入:root = [1]
输出:[1]
- public List<Integer> preorderTraversal(TreeNode root) {
- List<Integer> list = new ArrayList<>();
- preorderTraversalVal(root, list);
- return list;
- }
-
- public void preorderTraversalVal(TreeNode root, List list) {
- if(root == null) {
- return;
- }
-
- list.add(root.val);
- preorderTraversalVal(root.left, list);
- preorderTraversalVal(root.right, list);
- }
给定一个二叉树的根节点 root
,返回它的 中序 遍历。
输入:root = [1,null,2,3]
输出:[1,3,2]
示例 2:
输入:root = []
输出:[]
示例 3:
输入:root = [1]
输出:[1]
- public List<Integer> inorderTraversal(TreeNode root) {
- List<Integer> list = new ArrayList<>();
- inorderTraversalVal(root, list);
- return list;
- }
-
- public void inorderTraversalVal(TreeNode root, List list) {
- if (root == null) {
- return;
- }
- inorderTraversalVal(root.left, list);
- list.add(root.val);
- inorderTraversalVal(root.right, list);
- }
请实现一个函数,用来判断一棵二叉树是不是对称的。如果一棵二叉树和它的镜像一样,那么它是对称的。
例如,二叉树 [1,2,2,3,4,4,3] 是对称的。
- public boolean isSymmetric(TreeNode root) {
- if(root == null) {
- return true;
- }
-
- return symmetric(root.left, root.right);
- }
-
- public boolean symmetric(TreeNode left, TreeNode right) {
- if(left == null && right == null) {
- return true;
- }
-
- if(left == null || right == null) {
- return false;
- }
-
- return left.val == right.val && symmetric(left.left, right.right) && symmetric(left.right, right.left);
- }
请完成一个函数,输入一个二叉树,该函数输出它的镜像。
示例 1:
- 输入:root = [4,2,7,1,3,6,9]
- 输出:[4,7,2,9,6,3,1]
- public TreeNode mirrorTree(TreeNode root) {
- if(root == null) {
- return null;
- }
-
- Stack<TreeNode> stack = new Stack<>();
- stack.push(root);
-
- while(!stack.isEmpty()) {
- TreeNode node = stack.pop();
- if(node.left != null) {
- stack.push(node.left);
- }
-
- if(node.right != null) {
- stack.push(node.right);
- }
- TreeNode temp = node.left;
- node.left = node.right;
- node.right = temp;
-
- }
- return root;
- }
给你一个二叉树,请你返回其按 层序遍历 得到的节点值。 (即逐层地,从左到右访问所有节点)。
- public List<List<Integer>> levelOrder(TreeNode root) {
- if(root == null) {
- return new ArrayList<>();
- }
-
- Deque<TreeNode> queue = new ArrayDeque<>();
- queue.offer(root);
- List<List<Integer>> list = new ArrayList<>();
- while(!queue.isEmpty()) {
- List<Integer> levelList = new ArrayList<>();
- int size = queue.size();
- for(int i = 0; i < size; i ++) {
- TreeNode treeNode = queue.poll();
- levelList.add(treeNode.val);
- if(treeNode.left != null) {
- queue.offer(treeNode.left);
- }
- if(treeNode.right != null) {
- queue.offer(treeNode.right);
- }
-
- }
- list.add(levelList);
- }
- return list;
- }
输入一棵二叉树的根节点,求该树的深度。从根节点到叶节点依次经过的节点(含根、叶节点)形成树的一条路径,最长路径的长度为树的深度。
例如:
给定二叉树 [3,9,20,null,null,15,7],
返回它的最大深度 3 。
- public int maxDepth(TreeNode root) {
- if(root == null) {
- return 0;
- }
- return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;
- }
- public int maxDepth(TreeNode root) {
- if(root == null) {
- return 0;
- }
-
- int result = 0;
- List<TreeNode> list = new ArrayList<>();
- list.add(root);
- while(!list.isEmpty()) {
- List<TreeNode> temp = new ArrayList<>();
- for(TreeNode treeNode : list) {
- if(treeNode.left != null) {
- temp.add(treeNode.left);
- }
- if(treeNode.right != null) {
- temp.add(treeNode.right);
- }
- }
-
- list = temp;
- result ++;
- }
- return result;
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。