栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

LeetCode 笔记六

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

LeetCode 笔记六

LeetCode 笔记六
    • 一.乘积小于 K 的子数组
    • 二.重排链表
    • 三.二叉树的右视图
    • 四.下一个排列
    • 五.平衡二叉树

前言:主要是记录一些算法题的解题思路与技巧,纯当笔记用。

图片与部分代码来源:leetcode
图片与部分代码来源:leetcode
图片与部分代码来源:leetcode

一.乘积小于 K 的子数组

力扣链接:乘积小于 K 的子数组

这题就一个关键点,懂了这点,这题就会了。首先利用双指针扩展窗口直至当前窗口的乘积位于K的临界值,即再乘上下一个数,乘积会大于或等于K 。然后缩小窗口,即增加左指针的值缩小窗口,因为所有的数都是正数,所以相当于除了一个正数。如果之前的乘积是小于 K 的,那么除了一个正数之后也一定是小于K的。换一种表述,如果一个数组是符合要求的,那么它的一个子数组也一定是符合要求的, 所以计数可以直接加 right-left 。具体实现看代码。

class Solution {
public:

    int numSubarrayProductLessThanK(vector& nums, int k) {

        int left=0,right=0;   //左右指针
        int sum=1;
        int ret=0;      //计数
        while(right

            sum*=nums[right];   //类乘
            if(sum   //如果乘积小于K则继续类乘,并且计数加一

               ++right;
               ++ret;
            }
            else{     //如果乘积大于等于K则缩小窗口并且利用之前的计算结果避免重复计算

               sum/=nums[right];
               if(left!=right)
                  sum/=nums[left];

               ++left;
               if(right    //计算剩余的满足条件的子数组

              ++left;
              ret+=right-left;
        }
        
        return ret;
    }
};
二.重排链表

力扣链接:重排链表

很经典的一题,考察了链表的很多知识点。这题的最优解是是先用快慢指针分割链表,把一个链表分成相对平均的两半。反转其中的一半。然后再把这两个链表合并就行了。

class Solution {
public:
        
        ListNode* divis(ListNode* head){    //利用快慢指针分割链表

            ListNode* fast=head,*slow=head;
            while(fast){

                fast=fast->next;
                if(!fast)
                   return slow;
                
                fast=fast->next;
                if(!fast || !fast->next){

                    if(fast && !fast->next)
                       slow=slow->next;
                    ListNode* tmp=slow->next;
                    slow->next=nullptr;
                    return tmp;
                }
                else
                    slow=slow->next;
            }

            return slow;
        }

        ListNode* rever(ListNode* head){    //反转链表

            if(!head)
               return nullptr;
            ListNode* first=head,*second=first->next;
            first->next=nullptr;
            while(second){

                ListNode* third=second->next;
                second->next=first;
                first=second;
                second=third;
            }

            return first;
        }

        void reorderList(ListNode* head) {     //合并两个链表
            
             ListNode* first=head;
             ListNode* second=divis(head);
             second=rever(second);
             while(first && second){

                 ListNode* tmp=first->next;
                 ListNode* tmp1=second->next;

                 first->next=second;
                 first=tmp;

                 second->next=first;
                 second=tmp1;
             }

             return;
        }
};

三.二叉树的右视图

力扣链接:二叉树的右视图

方法一:

可以用递归做这题,具体的做法为先遍历二叉树的右子树,再遍历左子树,同时记录当前遍历到的二叉树层数。边遍历边把符合条件的值加入到结果数组中,当前值是否加入结果数组的条件为当前递归层数是否大于或等于结果数组中元素个数。如果大于等于,则把当前节点的值加入结果数组中。

class Solution {
public:

    int dfs(vector& ret,TreeNode* root,int count){

        if(!root)
           return 1;

        if(count>=ret.size())   //如果当前递归层数大于或等于结果数组中元素个数,则把当前节点的值加入到结果集中
           ret.push_back(root->val);
        
        dfs(ret,root->right,count+1);   //遍历右子树
        dfs(ret,root->left,count+1);    //遍历左子树

        return 1;
    }

    vector rightSideView(TreeNode* root) {

          vector ret;
          dfs(ret,root,0);

          return ret;
    }
};

方法二

也可以利用二叉树的层序遍历,只需要把二叉树每一层所有节点中的最右边的节点的值加入结果数组中就行了。

class Solution {
public:

    vector rightSideView(TreeNode* root) {

          vector ret;
          if(!root)
             return ret;
          queue que;
          que.push(root);
          while(que.size()){

              ret.push_back(que.back()->val);   //把二叉树当前层所有节点中的最右边的节点的值加入结果数组中
              int length=que.size();
              while(length){       //把当前层中所有节点加入队列

                  TreeNode* tmp=que.front();
                  que.pop();
                  if(tmp->left)
                     que.push(tmp->left);

                  if(tmp->right)
                     que.push(tmp->right);

                  --length;
              }
          }

          return ret;
    }
};
四.下一个排列

力扣链接:下一个排列

三步走:

  1. 找到一个较小数,使得他尽量往右靠;找到一个较大数,使得他尽量往右。(较小数应小于较大数)
  2. 交换两数。
  3. 把交换前较小数所在位置往后的所有数按升序排列。
class Solution {
public:
    void nextPermutation(vector& nums) {
        
         int left=nums.size()-2;
         while(left>=0 && nums[left]>=nums[left+1])   //找到较小数
               --left;
         if(left>=0){

             int right=nums.size()-1;
             while(right>=0 && nums[right]<=nums[left])   //找到较大数
                   --right;
             swap(nums[left],nums[right]);   //交换两数
         }

         sort(nums.begin() + left + 1, nums.end());   //升序排列
    }
};
五.平衡二叉树

力扣链接:平衡二叉树

很基础的一题,但有一个优化的小技巧,就是在下层二叉树已经不满足的条件的情况下可以加一个判断,避免递归函数进行多余的递归,以提高效率。

class Solution {
public:

    bool ret=true;

    int dfs(TreeNode* root){

        if(!root)
           return 0;

        if(!ret)    //如果子树已经不满足条件了,就没必要继续递归下去
           return 1;
        int left=dfs(root->left)+1;
        int right=dfs(root->right)+1;

        if(abs(left-right)>=2)   //如果左右子树差超过1,则不满足条件
           ret=false;
        
        return max(left,right);
    }

    bool isBalanced(TreeNode* root) {
         
         dfs(root);

         return ret;
    }
};
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/869218.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号