输入两棵二叉树A和B,判断B是不是A的子结构。(约定空树不是任意一个树的子结构)
B是A的子结构, 即 A中有出现和B相同的结构和节点值。
例如: 给定的树 A:
3
/ \
4 5
/ \
1 2
给定的树 B:
4
/
1
返回 true,因为 B 与 A 的一个子树拥有相同的结构和节点值。
示例 1:
输入:A = [1,2,3], B = [3,1] 输出:false 示例 2:
输入:A = [3,4,5,1,2], B = [4,1] 输出:true 限制:
0 <= 节点个数 <= 10000
链接:https://leetcode-cn.com/problems/shu-de-zi-jie-gou-lcof/
解法一:递归
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public boolean isSubStructure(TreeNode A, TreeNode B) {
if (B==null||A==null){
return false;
}
// 判断这棵树或左右子树
return contains(A,B)||isSubStructure(A.left,B)||isSubStructure(A.right,B);
}
public boolean contains(TreeNode A,TreeNode B){
if (B==null){
return true;
}
if (A==null||A.val!=B.val){
return false;
}
// 递归判断左右子树
return contains(A.left,B.left)&&contains(A.right,B.right);
}
}
请完成一个函数,输入一个二叉树,该函数输出它的镜像。
例如输入:
4
/ \
2 7
/ \ / \
1 3 6 9
镜像输出:
4
/ \
7 2
/ \ / \
9 6 3 1
示例 1:
输入:root = [4,2,7,1,3,6,9] 输出:[4,7,2,9,6,3,1]
限制:
0 <= 节点个数 <= 1000
链接:https://leetcode-cn.com/problems/er-cha-shu-de-jing-xiang-lcof/
解法一:递归
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode mirrorTree(TreeNode root) {
if (root==null){
return null;
}
TreeNode newTree = new TreeNode(root.val);
newTree.left = mirrorTree(root.right);
newTree.right = mirrorTree(root.left);
return newTree;
}
}
请实现一个函数,用来判断一棵二叉树是不是对称的。如果一棵二叉树和它的镜像一样,那么它是对称的。
例如,二叉树 [1,2,2,3,4,4,3] 是对称的。
1
/
2 2
/ \ /
3 4 4 3
但是下面这个 [1,2,2,null,3,null,3] 则不是镜像对称的:
1
/
2 2
\
3 3
示例 1:
输入:root = [1,2,2,3,4,4,3] 输出:true 示例 2:
输入:root = [1,2,2,null,3,null,3] 输出:false
限制:
0 <= 节点个数 <= 1000
链接:https://leetcode-cn.com/problems/dui-cheng-de-er-cha-shu-lcof/
解法一:递归
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public boolean isSymmetric(TreeNode root) {
if (root==null){
return true;
}
// 递归
return recur(root.left,root.right);
}
public boolean recur(TreeNode A,TreeNode B){
if (A==null&&B==null){
return true;
}
// 失败条件
if (A==null||B==null||A.val!=B.val){
return false;
}
// 比较A的左子树和B的右子树,A的右子树和B的左子树
return recur(A.left,B.right)&&recur(A.right,B.left);
}
}
假设把某股票的价格按照时间先后顺序存储在数组中,请问买卖该股票一次可能获得的最大利润是多少?
示例 1:
输入: [7,1,5,3,6,4] 输出: 5 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。 注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。 示例 2:
输入: [7,6,4,3,1] 输出: 0 解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。
限制:
0 <= 数组长度 <= 10^5
链接:https://leetcode-cn.com/problems/gu-piao-de-zui-da-li-run-lcof/
解法一:暴力
class Solution {
public int maxProfit(int[] prices) {
int maxProfit = 0;
for (int i=0;i<prices.length;i++){
for (int j=i;j<prices.length;j++){
if (prices[j]-prices[i]>maxProfit){
maxProfit = prices[j]-prices[i];
}
}
}
return maxProfit;
}
}
解法二:一次遍历,记录当前点之前的最小值,计算最大利润
最大利润 = Max(之前的最大利润,现价 - 之前的最小花费)
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/gu-piao-de-zui-da-li-run-lcof/solution/gu-piao-de-zui-da-li-run-by-leetcode-sol-0l1g/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
输入一个整型数组,数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。
要求时间复杂度为O(n)。
示例1:
输入: nums = [-2,1,-3,4,-1,2,1,-5,4] 输出: 6 解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
提示:
1 <= arr.length <= 10^5 -100 <= arr[i] <= 100 注意:本题与主站 53 题相同:https://leetcode-cn.com/problems/maximum-subarray/
链接:https://leetcode-cn.com/problems/lian-xu-zi-shu-zu-de-zui-da-he-lcof/
解法一:动态规划
求出每个位置的最大值,返回最大值中最大的数。
对于一个位置的最大值,dp[i] = Max(dp[i-1]+nums[i],nums[i])
class Solution {
public int maxSubArray(int[] nums) {
int max = nums[0];
int[] dp = new int[nums.length];
dp[0] = nums[0];
for (int i=1;i<nums.length;i++){
if (nums[i]+dp[i-1]>=nums[i]){
dp[i] = nums[i]+dp[i-1];
}else{
dp[i] = nums[i];
}
if (max<dp[i]){
max = dp[i];
}
}
return max;
}
}
在一个 m*n 的棋盘的每一格都放有一个礼物,每个礼物都有一定的价值(价值大于 0)。你可以从棋盘的左上角开始拿格子里的礼物,并每次向右或者向下移动一格、直到到达棋盘的右下角。给定一个棋盘及其上面的礼物的价值,请计算你最多能拿到多少价值的礼物?
示例 1:
输入: [ [1,3,1], [1,5,1], [4,2,1] ] 输出: 12 解释: 路径 1→3→5→2→1 可以拿到最多价值的礼物
提示:
0 < grid.length <= 200 0 < grid[0].length <= 200
链接:https://leetcode-cn.com/problems/li-wu-de-zui-da-jie-zhi-lcof/
解法一:动态规划
用一个数组保存当前位置所能得到的最大价值,最后数组右下角就是整个棋盘能得到的最大价值。
由于仅能向右或向下移动,(i,j)的最大价值为Max(左边值,上边值)+ (i,j)的值,公式为:dp[i][j] = Max(dp[i-1][j],dp[i][j-1]) + grid[i][j]
class Solution {
public int maxValue(int[][] grid) {
int[][] dp = new int[grid.length][grid[0].length];
dp[0][0] = grid[0][0];
int m = grid.length;
int n = grid[0].length;
// 先初始化第一行和第一列,减少后面再处理
for (int i=1;i<grid.length;i++){
dp[i][0] = dp[i-1][0]+grid[i][0];
}
for (int i=1;i<grid[0].length;i++){
dp[0][i] = dp[0][i-1]+grid[0][i];
}
for (int i=1;i<grid.length;i++){
for (int j=1;j<grid[0].length;j++){
dp[i][j] = Math.max(dp[i-1][j],dp[i][j-1])+grid[i][j];
}
}
return dp[m-1][n-1];
}
}
给定一个数字,我们按照如下规则把它翻译为字符串:0 翻译成 “a” ,1 翻译成 “b”,……,11 翻译成 “l”,……,25 翻译成 “z”。一个数字可能有多个翻译。请编程实现一个函数,用来计算一个数字有多少种不同的翻译方法。
示例 1:
输入: 12258 输出: 5 解释: 12258有5种不同的翻译,分别是"bccfi", "bwfi", "bczi", "mcfi"和"mzi"
提示:
0 <= num < 231
链接:https://leetcode-cn.com/problems/ba-shu-zi-fan-yi-cheng-zi-fu-chuan-lcof/
解法一:动态规划
将求解过程分解,12258分解为:1->12->122->1225->12258。
每个数字有两种情况:可以和前面数字组合为一个字母(和前面的数字组成大于9小于26的数字)对结果贡献的递推方程:f(i) = f(i-1) + f(i-2);不可以和前面数字组合为一个字母,对结果贡献为0。针对不同情况进行判断.
class Solution {
public int translateNum(int num) {
String str = String.valueOf(num);
int[] dp = new int[str.length()];
dp[0] = 1;
for (int i=1;i<str.length();i++){
int i1 = Integer.parseInt(str.substring(i - 1, i + 1));
if (i1<26&& i1 >9){
if (i>1){
dp[i] = dp[i-1] + dp[i-2];
}else{
dp[i] = dp[i-1]+1;
}
}else{
dp[i] = dp[i-1];
}
}
return dp[str.length()-1];
}
}
请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。
示例 1:
输入: "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。 示例 2:
输入: "bbbbb" 输出: 1 解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。 示例 3:
输入: "pwwkew" 输出: 3 解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。 请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
提示:
s.length <= 40000
链接:https://leetcode-cn.com/problems/zui-chang-bu-han-zhong-fu-zi-fu-de-zi-zi-fu-chuan-lcof/
解法一:遍历生成子串
按条件生成所有不重复子串,用一个变量保存最长的子串
class Solution {
public int lengthOfLongestSubstring(String s) {
if (s==null||s.isEmpty()){
return 0;
}
String maxS = String.valueOf(s.charAt(0));
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(s.charAt(0));
for (int i=1;i<s.length();i++){
if (stringBuilder.indexOf(String.valueOf(s.charAt(i)))>-1){
if (maxS.length()<stringBuilder.length()){
maxS = stringBuilder.toString();
}
stringBuilder = new StringBuilder(stringBuilder.substring(stringBuilder.indexOf(String.valueOf(s.charAt(i)))+1, stringBuilder.length()));
}
stringBuilder.append(s.charAt(i));
if (maxS.length()<stringBuilder.length()){
maxS = stringBuilder.toString();
}
}
return maxS.length();
}
}
解法二:动态规划 + 哈希表
双指针,i记录元素首次出现位置,j记录本次出现位置,相减就可得不含重复字符的长度。需要用一个哈希表记录元素的位置
class Solution {
public int lengthOfLongestSubstring(String s) {
Map<Character, Integer> dic = new HashMap<>();
int res = 0, tmp = 0;
for(int j = 0; j < s.length(); j++) {
int i = dic.getOrDefault(s.charAt(j), -1); // 获取索引 i
dic.put(s.charAt(j), j); // 更新哈希表
tmp = tmp < j - i ? tmp + 1 : j - i; // dp[j - 1] -> dp[j]
res = Math.max(res, tmp); // max(dp[j - 1], dp[j])
}
return res;
}
}
作者:jyd
链接:https://leetcode-cn.com/problems/zui-chang-bu-han-zhong-fu-zi-fu-de-zi-zi-fu-chuan-lcof/solution/mian-shi-ti-48-zui-chang-bu-han-zhong-fu-zi-fu-d-9/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。
返回删除后的链表的头节点。
注意:此题对比原题有改动
示例 1:
输入: head = [4,5,1,9], val = 5 输出: [4,1,9] 解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9. 示例 2:
输入: head = [4,5,1,9], val = 1 输出: [4,5,9] 解释: 给定你链表中值为 1 的第三个节点,那么在调用了你的函数之后,该链表应变为 4 -> 5 -> 9.
说明:
题目保证链表中节点的值互不相同 若使用 C 或 C++ 语言,你不需要 free 或 delete 被删除的节点
链接:https://leetcode-cn.com/problems/shan-chu-lian-biao-de-jie-dian-lcof/
解法一:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode deleteNode(ListNode head, int val) {
if (head==null){
return null;
}
if (head.val == val){
return head.next;
}
ListNode h1 = head;
ListNode last = head;
head = head.next;
while (head!=null){
if (head.val==val){
last.next = head.next;
break;
}else{
last = head;
head = head.next;
}
}
return h1;
}
}
输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点。
例如,一个链表有 6 个节点,从头节点开始,它们的值依次是 1、2、3、4、5、6。这个链表的倒数第 3 个节点是值为 4 的节点。
示例:
给定一个链表: 1->2->3->4->5, 和 k = 2.
返回链表 4->5.
链接:https://leetcode-cn.com/problems/lian-biao-zhong-dao-shu-di-kge-jie-dian-lcof/
解法一:双指针(快慢指针)
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode getKthFromEnd(ListNode head, int k) {
ListNode p1 = head;
ListNode p2 = head;
int i=0;
while (p2!=null&&i++<k){
p2 = p2.next;
}
while (p2!=null){
p1 = p1.next;
p2 = p2.next;
}
return p1;
}
}
输入两个递增排序的链表,合并这两个链表并使新链表中的节点仍然是递增排序的。
示例1:
输入:1->2->4, 1->3->4 输出:1->1->2->3->4->4 限制:
0 <= 链表长度 <= 1000
解法一:遍历、比较、逐个添加到新的头节点
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
if (l1==null){
return l2;
}
if (l2==null){
return l1;
}
ListNode head;
ListNode l;
if (l1.val>l2.val){
l = l2;
l2 = l2.next;
}else{
l = l1;
l1 = l1.next;
}
head = l;
while (l1!=null&&l2!=null){
if (l1.val<l2.val){
l.next = l1;
l = l.next;
l1 = l1.next;
}else {
l.next = l2;
l = l.next;
l2 = l2.next;
}
}
while (l1!=null){
l.next = l1;
l = l.next;
l1 = l1.next;
}
while (l2!=null){
l.next = l2;
l = l.next;
l2 = l2.next;
}
return head;
}
}
输入两个链表,找出它们的第一个公共节点。
如下面的两个链表:
在节点 c1 开始相交。
示例 1:
输入: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 个节点。
示例 2:
输入:intersectVal = 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1 输出:Reference of the node with value = 2 输入解释:相交节点的值为 2 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [0,9,1,2,4],链表 B 为 [3,2,4]。在 A 中,相交节点前有 3 个节点;在 B 中,相交节点前有 1 个节点。
示例 3:
输入:intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2 输出:null 输入解释:从各自的表头开始算起,链表 A 为 [2,6,4],链表 B 为 [1,5]。由于这两个链表不相交,所以 intersectVal 必须为 0,而 skipA 和 skipB 可以是任意值。 解释:这两个链表不相交,因此返回 null。
注意:
如果两个链表没有交点,返回 null. 在返回结果后,两个链表仍须保持原有的结构。 可假定整个链表结构中没有循环。 程序尽量满足 O(n) 时间复杂度,且仅用 O(1) 内存。 本题与主站 160 题相同:https://leetcode-cn.com/problems/intersection-of-two-linked-lists/
链接:https://leetcode-cn.com/problems/liang-ge-lian-biao-de-di-yi-ge-gong-gong-jie-dian-lcof/
解法一:计算两个链表的长度差,让长的链表先走几步,再让两个链表同步遍历寻找相同的节点
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
int a=0;
int b=0;
ListNode h1 = headA;
ListNode h2 = headB;
while (headA!=null&&headB!=null){
headA = headA.next;
headB = headB.next;
a++;
b++;
}
while (headA!=null){
a++;
headA = headA.next;
}
while (headB!=null){
b++;
headB = headB.next;
}
if (a>b){
for (int i=0;i<a-b;i++){
h1 = h1.next;
}
}
if (b>a){
for (int i=0;i<b-a;i++){
h2 = h2.next;
}
}
while(h1!=null&&h2!=null){
if (h1==h2){
return h1;
}else{
h1 = h1.next;
h2 = h2.next;
}
}
return null;
}
}
解法二:双指针
public class Solution {
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;
}
}
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/liang-ge-lian-biao-de-di-yi-ge-gong-gong-jie-dian-lcof/solution/liang-ge-lian-biao-de-di-yi-ge-gong-gong-pzbs/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数在数组的前半部分,所有偶数在数组的后半部分。
示例:
输入:nums = [1,2,3,4] 输出:[1,3,2,4] 注:[3,1,2,4] 也是正确的答案之一。
提示:
链接:https://leetcode-cn.com/problems/diao-zheng-shu-zu-shun-xu-shi-qi-shu-wei-yu-ou-shu-qian-mian-lcof/
解法一:双指针
class Solution {
public int[] exchange(int[] nums) {
int low = 0;
int high = nums.length-1;
while (low<high){
if (nums[low]%2==0&&nums[high]%2!=0){
int tmp = nums[low];
nums[low] = nums[high];
nums[high] = tmp;
low++;
high--;
}else if (nums[low]%2!=0&&nums[high]%2==0){
low++;
high--;
}else if (nums[low]%2==0&&nums[high]%2==0){
high--;
}else if (nums[low]%2!=0&&nums[high]%2!=0){
low++;
}
}
return nums;
}
}
输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得它们的和正好是s。如果有多对数字的和等于s,则输出任意一对即可。
示例 1:
输入:nums = [2,7,11,15], target = 9 输出:[2,7] 或者 [7,2] 示例 2:
输入:nums = [10,26,30,31,47,60], target = 40 输出:[10,30] 或者 [30,10]
限制:
链接:https://leetcode-cn.com/problems/he-wei-sde-liang-ge-shu-zi-lcof/
解法一:双指针
class Solution {
public int[] twoSum(int[] nums, int target) {
int low = 0;
int high = nums.length-1;
while (low<high){
if (nums[low]+nums[high]<target){
low++;
}else if (nums[low]+nums[high]>target){
high--;
}else{
int[] n = new int[2];
n[0] = nums[low];
n[1] = nums[high];
return n;
}
}
return null;
}
}
输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。为简单起见,标点符号和普通字母一样处理。例如输入字符串"I am a student. ",则输出"student. a am I"。
示例 1:
输入: "the sky is blue" 输出: "blue is sky the" 示例 2:
输入: " hello world! " 输出: "world! hello" 解释: 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。 示例 3:
输入: "a good example" 输出: "example good a" 解释: 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。
说明:
无空格字符构成一个单词。 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。
链接:https://leetcode-cn.com/problems/fan-zhuan-dan-ci-shun-xu-lcof/
解法一:使用Java库函数和正则
class Solution {
public String reverseWords(String s) {
String[] strs = s.split("\\s+");
int low = 0;
int high = strs.length-1;
while (low<high){
String tmp = strs[low];
strs[low] = strs[high];
strs[high] = tmp;
low++;
high--;
}
return String.join(" ", strs).trim();
}
}
解法二:双指针
class Solution {
public String reverseWords(String s) {
s = s.trim(); // 删除首尾空格
int j = s.length() - 1, i = j;
StringBuilder res = new StringBuilder();
while(i >= 0) {
while(i >= 0 && s.charAt(i) != ' ') i--; // 搜索首个空格
res.append(s.substring(i + 1, j + 1) + " "); // 添加单词
while(i >= 0 && s.charAt(i) == ' ') i--; // 跳过单词间空格
j = i; // j 指向下个单词的尾字符
}
return res.toString().trim(); // 转化为字符串并返回
}
}
作者:jyd
链接:https://leetcode-cn.com/problems/fan-zhuan-dan-ci-shun-xu-lcof/solution/mian-shi-ti-58-i-fan-zhuan-dan-ci-shun-xu-shuang-z/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。