剑指offer刷题笔记(七)

剑指offer刷题笔记(七)



剑指 Offer 53 - I. 在排序数组中查找数字 I
  • 统计一个数字在排序数组中出现的次数。
示例 1:
输入: nums = [5,7,7,8,8,10], target = 8
输出: 2
示例 2:
输入: nums = [5,7,7,8,8,10], target = 6
输出: 0

二分查找,找出左边界和右边界即可。

class Solution {
    public int search(int[] nums, int target) {
        if(nums.length==0){
            return 0;
        }
        return right(nums,target)-left(nums,target)+1;
    }

    private int left(int[] nums, int target) {
        int left=0;
        int right=nums.length-1;
        while (left<=right){
            int mid=(left+right)>>>1;
            if(nums[mid]<target){
                left=mid+1;
            }
            else{
                right=mid-1;
            }
        }
        return left;
    }
    private int right(int[] nums, int target) {
        int left=0;
        int right=nums.length-1;
        while (left<=right){
            int mid=(left+right)>>>1;
            if(nums[mid]<=target){
                left=mid+1;
            }
            else{
                right=mid-1;
            }
        }
        return right;
    }
}

剑指 Offer 53 - II. 0~n-1中缺失的数字
  • 一个长度为n-1的递增排序数组中的所有数字都是唯一的,并且每个数字都在范围0~n-1之内。在范围0~n-1内的n个数字中有且只有一个数字不在该数组中,请找出这个数字。
示例 1:
输入: [0,1,3]
输出: 2
示例 2:
输入: [0,1,2,3,4,5,6,7,9]
输出: 8

二分

class Solution {
    public int missingNumber(int[] nums) {
        if(nums.length==0){
            return -1;
        }
        return getNumber(nums,0,nums.length-1);
    }
    public int getNumber(int[]nums,int left,int right){
        while(left<=right){
            int mid=(left+right)>>>1;
            if(nums[mid]==mid){
                left=mid+1;
            }
            else if(nums[mid]>mid){
                right=mid-1;
            }
        }
        return left;
    }
}

剑指 Offer 54. 二叉搜索树的第k大节点
  • 给定一棵二叉搜索树,请找出其中第k大的节点。
示例 1:
输入: root = [3,1,4,null,2], k = 1
   3
  / \
 1   4
  \
   2
输出: 4
示例 2:
输入: root = [5,3,6,2,4,null,null,1], k = 3
       5
      / \
     3   6
    / \
   2   4
  /
 1
输出: 4

中序遍历倒序排布,就是一个递增的序列。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    int res;
    int k;
    public int kthLargest(TreeNode root, int k) {
        this.k=k;
        dfs(root);
        return res;
    }
    private void dfs(TreeNode root) {
        if(root==null){
            return;
        }
        dfs(root.right);
        if(k==0){
            return;
        }
        if(--k==0){
            res=root.val;
        }
        dfs(root.left);
    }
}

剑指 Offer 55 - I. 二叉树的深度
  • 输入一棵二叉树的根节点,求该树的深度。从根节点到叶节点依次经过的节点(含根、叶节点)形成树的一条路径,最长路径的长度为树的深度
    例如:
    给定二叉树 [3,9,20,null,null,15,7],
   3
   / \
  9  20
    /  \
   15   7

返回它的最大深度 3 。

/**
 * 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;
        }
        int left=maxDepth(root.left);
        int right=maxDepth(root.right);
        return left>right?left+1:right+1;
    }
}

剑指 Offer 55 - II. 平衡二叉树
  • 输入一棵二叉树的根节点,判断该树是不是平衡二叉树。如果某二叉树中任意节点的左右子树的深度相差不超过1,那么它就是一棵平衡二叉树。
示例 1:
给定二叉树 [3,9,20,null,null,15,7]
    3
   / \
  9  20
    /  \
   15   7
返回 true 。
示例 2:
给定二叉树 [1,2,2,3,3,null,null,4,4]
       1
      / \
     2   2
    / \
   3   3
  / \
 4   4
返回 false 。

后序遍历,自底向上,不会遍历重复节点。看了评论区大佬才想到剪枝,直接筛去不符合条件的不在继续往下遍历。

class Solution {
    public boolean isBalanced(TreeNode root) {
        return balanced(root)!=-1;
    }

    private int balanced(TreeNode root) {
        if(root==null){
            return 0;
        }
        int left=balanced(root.left);
        if(left==-1){
            return -1;
        }
        int right=balanced(root.right);
        if(right==-1){
            return -1;
        }
        return Math.abs(left-right)<2?Math.max(left,right)+1:-1;
    }
}

剑指 Offer 56 - I. 数组中数字出现的次数
  • 一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
示例 1:
输入:nums = [4,1,4,6]
输出:[1,6] 或 [6,1]
示例 2:
输入:nums = [1,2,10,4,1,4,3,3]
输出:[2,10] 或 [10,2]

https://leetcode-cn.com/problems/shu-zu-zhong-shu-zi-chu-xian-de-ci-shu-lcof/solution/jie-di-qi-jiang-jie-fen-zu-wei-yun-suan-by-eddievi/
异或,找到两个不同的数,然后分组异或

class Solution {
    public int[] singleNumbers(int[] nums) {
        int k=0;
        for (int num:nums
             ) {
            k^=num;
        }
        k=k&(-k);
        int a=0;
        int b=0;
        for (int num:nums
             ) {
            if((k&num)==0){
              a^=num;  
            }
            else{
                b^=num;
            }
        }
        return new int[]{a,b};
    }
}

剑指 Offer 56 - II. 数组中数字出现的次数 II
  • 在一个数组 nums 中除一个数字只出现一次之外,其他数字都出现了三次。请找出那个只出现一次的数字。
示例 1:
输入:nums = [3,4,3,3]
输出:4
示例 2:
输入:nums = [9,1,7,9,7,9,7]
输出:1

异或操作,全体相加,对3取余。

class Solution {
    public int singleNumber(int[] nums) {
        if(nums.length==0){
            return -1;
        }
        int res=0;
        int[] b=new int[32];
        for(int num:nums){
            int bit=1;
            for(int i=31;i>=0;i--){
                if((num&bit)!=0){
                    b[i]++;
                }
                bit=bit<<1;
            }
        }
        for(int i=0;i<32;i++){
            res=res<<1;
            res+=b[i]%3;
        }
        return res;
    }
}

剑指 Offer 57. 和为s的两个数字
  • 输入一个递增排序的数组和一个数字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]

双指针移动

class Solution {
    public int[] twoSum(int[] nums, int target) {
        int i=0;
        int j=nums.length-1;
        while(i<j){
            if(nums[i]+nums[j]>target){
                j--;
            }
            else if(nums[i]+nums[j]<target){
                i++;
            }
            else{
                return new int[]{nums[i],nums[j]};
            }
        }
        return new int[0];
    }
}

剑指 Offer 57 - II. 和为s的连续正数序列
  • 输入一个正整数 target ,输出所有和为 target 的连续正整数序列(至少含有两个数)。
    序列内的数字由小到大排列,不同序列按照首个数字从小到大排列。
示例 1:
输入:target = 9
输出:[[2,3,4],[4,5]]
示例 2:
输入:target = 15
输出:[[1,2,3,4,5],[4,5,6],[7,8]]

双指针移动,滑动窗口

class Solution {
    List<int[]> list=new ArrayList<>();
    public int[][] findContinuousSequence(int target) {
        if(target==1||target==2){
            return new int[][]{};
        }
        int small=1;
        int big=2;
        int sum=big+small;
        int middle=(1+target)/2;
        while(small<middle){
            if(sum>target){
                sum-=small;
                small++;
            }
            else if(sum<target){
                big++;
                sum+=big;
            }
            else{
                //存储
                int[] r=new int[big-small+1];
                for (int i = small; i <big+1; i++) {
                    r[i-small]=i;
                }
                list.add(r);
                sum-=small;
                small++;
            }
        }
        return list.toArray(new int[list.size()][]);
    }
}

剑指 Offer 58 - I. 翻转单词顺序
  • 输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。为简单起见,标点符号和普通字母一样处理。例如输入字符串"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"
解释: 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。

从尾向前遍历,遍历完一个单词添加入结果字符串中。

class Solution {
    public String reverseWords(String s) {
        s=s.trim();
        int i=s.length()-1;
        int j=i;
        StringBuilder res=new StringBuilder();
        while(j>=0){
            while(j>=0&&s.charAt(j)!=' ')j--;
            res.append(s.substring(j+1,i+1)+" ");
            while(j>=0&&s.charAt(j)==' ')j--;
            i=j;
        }
        return res.toString().trim();
    }
}
剑指 Offer 58 - II. 左旋转字符串
  • 字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"abcdefg"和数字2,该函数将返回左旋转两位得到的结果"cdefgab"。
示例 1:
输入: s = "abcdefg", k = 2
输出: "cdefgab"
示例 2:
输入: s = "lrloseumgh", k = 6
输出: "umghlrlose"

字符串切片,拼接

class Solution {
    public String reverseLeftWords(String s, int n) {
        return s.substring(n)+s.substring(0,n);
    }
}

剑指 Offer 59 - I. 滑动窗口的最大值
  • 给定一个数组 nums 和滑动窗口的大小 k,请找出所有滑动窗口里的最大值。
示例:

输入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3
输出: [3,3,5,5,6,7] 
解释: 

  滑动窗口的位置                最大值
---------------               -----
[1  3  -1] -3  5  3  6  7       3
 1 [3  -1  -3] 5  3  6  7       3
 1  3 [-1  -3  5] 3  6  7       5
 1  3  -1 [-3  5  3] 6  7       5
 1  3  -1  -3 [5  3  6] 7       6
 1  3  -1  -3  5 [3  6  7]      7

https://leetcode-cn.com/problems/hua-dong-chuang-kou-de-zui-da-zhi-lcof/solution/java-dan-diao-shuang-xiang-lian-biao-hua-tu-xiang-/
构建一个双向递减队列。

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        if(nums.length==0||k<1||nums.length<k){
            return new int[]{};
        }
        int p=0;
        LinkedList<Integer> list=new LinkedList<>();
        int[] res=new int[nums.length-k+1];
        for (int i = 0; i <nums.length ; i++) {
        //必须是<=,更新索引
            while(!list.isEmpty()&&nums[list.peekLast()]<=nums[i]){
                list.pollLast();
            }
            list.addLast(i);
            //当最大值索引不在窗口中时,弹出
            if(list.peekFirst()==i-k){
                list.pollFirst();
            }
            if(i>=k-1){
                res[p++]=nums[list.peekFirst()];
            }
        }
        return res;
    }
}

剑指 Offer 59 - II. 队列的最大值
  • 请定义一个队列并实现函数 max_value 得到队列里的最大值,要求函数max_value、push_back 和 pop_front 的均摊时间复杂度都是O(1)。
    若队列为空,pop_front 和 max_value 需要返回 -1
示例 1:
输入: 
["MaxQueue","push_back","push_back","max_value","pop_front","max_value"]
[[],[1],[2],[],[],[]]
输出: [null,null,null,2,1,2]
示例 2:
输入: 
["MaxQueue","pop_front","max_value"]
[[],[],[]]
输出: [null,-1,-1]

与上一题基本类似,构建一个单向递减队列

class MaxQueue {
    private LinkedList<Integer> max;
    private LinkedList<Integer> list;
    public MaxQueue() {
        max=new LinkedList<>();
        list=new LinkedList<>();
    }

    public int max_value() {
        if(max.isEmpty()){
            return -1;
        }
        return max.peekFirst();
    }
    public void push_back(int value) {
        list.add(value);
        while(!max.isEmpty()&&max.peekLast()<value)
            max.removeLast();
        max.add(value);
    }

    public int pop_front() {
        if(list.isEmpty()){
            return -1;
        }
        if(max.peekFirst().equals(list.peek()))
            max.removeFirst();
        return list.poll();
    }
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342