备战蓝桥 2021-12-31

这篇博客主要探讨了二分查找的实现细节,包括两种不同的区间划分方法,并通过代码展示了如何使用二分查找模板。接着,讨论了如何在数组中移除特定元素,强调了元素覆盖和双指针优化的思路。最后,介绍了带分数问题的解决策略,通过列举1到9的所有全排列并进行分组,来确保找到满足条件的带分数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

二分查找

题目

在这里插入图片描述

思路

这道题就是一道很简单的二分查找,但也有我们很多要注意的地方,区间的划分最为关键。
其实区间划分的问题,一般我们有两种区间划分的方法,1,[left,right-1] 2,[left,right) ,这两种划分是等价的,其次你还要搞明白,[right,right]这个区间是有意思的,因为你可以取到right这个位置的值,而[right,right)这个区间是没有意义的,因为你取不到right这个地方的值。当你明白了这几个点了之后,区间的划分就变的十分简单了。

首先的先用之前在y总那记的二分模板来写了下。

          /*  y总那学习的模板
          int r=nums.size()-1,l=0,mid=0;
          while(l<r)
          {
              mid=(l+r)>>1;
              if(nums[mid]>=target)  r=mid;
              else l=mid+1;
          }
          if(nums[r]==target) return r;
          else return -1;
          */

他的模板确实很简单,这是不易理解, 很多人可能第一感觉应该是写if(nums[mid]=target) return mid,其实是不行的,你只要去举几个例子就知道了,写成nums[r]和nums[l]都是可以的。

代码随想录那儿的两种写法
1,区间划分成[left,right]

//取左闭右闭区间
          /*int left=0,right=nums.size()-1; //因为是右闭,所以这儿right取nums.size()-1
          int mid=0;
          while(left<=right)  //这儿要有等于号,因为当left==right时,【right,right】这个区间也是有意义的
          {
              mid=(left+right)>>1;
              if(nums[mid]>target)  right=mid-1;  // 此时说明答案在mid的左边,而且mid这个位置
                                                  //一定大于target,且区间是右闭,所以区间更新
                                                  // 为【0,mid-1】
              else if(nums[mid]<target) left=mid+1; //理由和推理同上
              else  return mid;
          }
          return -1;*/

2,区间划分成[left,nums.size() )

 //左闭右开的写法
          int left=0,right=nums.size(); //因为右区间开的,所以区间[0,nums.size() )可以确保遍历
                                        //完整个数组 
          int mid=0;
          while(left<right)   //因为是左开右闭,所以当left==right时,[right,right)这个区间是没有
                              //意义的
        {
            mid=(left+right)>>1;
            if(nums[mid]>target)  right=mid; //此时说明答案在左区间[left,mid-1],而这种情况的
                                             //为左开右闭,所以区间[left,mid)等价于[left,mid-1]
            else if(nums[mid]<target)  left=mid+1; // 此时说明答案在右区间[mid+1,nums.size-1]
                                                   // 而区间[mid+1,nums.size)等价于此区间
            else return mid;
        }
        return -1;

移除元素

题目

在这里插入图片描述

思路

首先要明白一点,要想从数组中移除元素肯定是不可能的,因为数组中的空间是连续的,所以我们只能采用元素覆盖的方法,想到这,一个思路也就来了:我们可以用一个for循环遍历数组,找到等于val的位置,然后将其之后的元素往前移一位,达到覆盖它的目的。

    int size=nums.size();
    for(int i=0;i<size;i++)
    {
        if(nums[i]==val)
        {
            for(int j=i+1;j<size;j++)
            {
                    nums[j-1]=nums[j];
            }
            i--;
            size--;
        }
    }
    return size;

注意:要记得i–和size–,因为你将后面所有的元素往前移一位时,你i本身这个位置也要往前移一位,同时你覆盖了你个等于val的位置,所以要size–。

像这种两层for循环可以暴力求解的题目,往往可以用双指针来优化,已达到用一个for循环就可以做出来的目的。

        /*  双指针法
        int fast=0,slow=0;
        for(fast=0;fast<nums.size();fast++)
        {
            if(nums[fast]!=val)
            {
                nums[slow++]=nums[fast];
            }
        }
        return slow;

带分数

题目

在这里插入图片描述
刚拿到这题时我是迷茫的,根本没有任何的思路,我一开始想找找看,是否具有什么规律,发现并不行,因为你无法确保它里面包含每一个数字。后来看了题解之后,才恍然大悟,既然我们不能正向推导,保证它里面包含所有的数字,那为什么我们不反过来想了,我们列举出1到9的所有全排列,然后将这9个数分成3组,分别对应这a,b,c,这样就确保了a,b,c这三个数中一定包含了1到9,而且不会有重复,之后我们判断a,b,c这三个数是否满足等于n的关系即可。

#include<iostream>
using namespace std;
const int N=10;
int backup[N]; //用来存放不同排列组合结果的数组
bool st[N];
int n;
int res;

int cal(int l,int r)  //将数组中的数分离出来的方法。
{
    int ans=0;
    for(int i=l;i<=r;i++)
    {
        ans=ans*10+backup[i];
    }
    return ans;
}


void dfs(int u)
{
    if(u>9)  //因为数组是从1开始放的,所以最后结束的时候是10
    {
        for(int i=1;i<8;i++)   //因为存放的数组是从1开始的
        {
            for(int j=i+1;j<9;j++)
            {
                    int a=cal(0,i);
                    int b=cal(i+1,j);
                    int c=cal(j+1,9);
                    if(a*c+b==n*c)
                    {
                        res++;
                    }
            }
        }
        return ;
    }
    
    for(int i=1;i<=9;i++)
    {
        if(!st[i])
        {
            st[i]=true;
            backup[u]=i;
            dfs(u+1);
            backup[u]=0;
            st[i]=false;
        }
    }
}

int main()
{
    cin>>n;
    dfs(1);  //按照我正常的习惯,做dfs时数组从第一个位置开始放      
    cout<<res<<endl;
    return 0;
}
对于零基础的同学来说,备战蓝桥杯Python组确实需要系统化的学习计划。下面是一些建议帮助你从入门到具备参赛能力: ### 一、基础知识积累阶段 **1. 学习 Python 编程语言** - **语法基础** - 数据类型(整数、浮点数、字符串等)、运算符及表达式 - 控制结构:条件判断 if...elif...else; 循环 for 和 while;break 和 continue 等控制流关键词 - **函数编写** - 定义与调用自定义函数 - 参数传递机制包括位置参数、默认值参数以及关键字参数的概念 - 函数内部作用域规则理解局部变量和全局变量的区别 - **数据容器操作** - 列表(List):索引访问元素、切片获取片段、增删改查列表项内容的操作方法 - 元祖(Tuple): 只读特性使其适用于某些特定场景下作为不可变序列的数据存储形式之一 - 字典(Dictionary):键值对映射关系建立及其基本查询修改方式 - 集合(Set):无序集合的特点决定了它适合用于去除重复项或者求交集并集差集之类的应用场合 - **文件处理** - 文件打开模式(r,w,a,b,t,x) - 使用 with as 的上下文管理器进行资源自动释放的安全编码习惯养成 - 文本型 vs 二进制型 I/O 流区别对待原则 - **模块导入** - 标准库简介如 os, sys 模块功能介绍 - 第三方包安装 pip 工具的基本运用技巧 **2. 掌握常用算法思想** 掌握常见的排序算法(冒泡法 冒泡排序、插入排序...)查找算法(顺序搜索 折半查找),并且了解其时间复杂度空间复杂度分析框架。 ### 二、刷题实践巩固提高阶段 选择一些在线 OJ 平台开始练习,比如力扣 (LeetCode), 牛客网(NiuKe), 蓝桥云课等等,通过大量做历届真题加深印象,并学会总结归纳相似类型的解题套路模板。注意: - 记录错题反思原因避免下次再犯错误; - 尽量尝试多种解决方案对比效率差异之处所在; - 向优秀的选手请教思路开阔眼界增长见识。 最后提醒一点就是保持良好心态,毕竟准备比赛是一个长期过程,遇到困难不要轻易放弃。只要坚持不懈地按照上述步骤努力下去,相信你在比赛中一定能取得理想成绩!
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一个数学不怎么好的程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值