编程之美问题记录——数字之魅1

2024-03-27 22:38

本文主要是介绍编程之美问题记录——数字之魅1,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

抽出一部分时间看了一点编程之美,思考的乐趣确实是一种享受。

求二进制中1的个数

分析:直接判断每一位,时间O(log2(n))。可以只判断”1”的个数。
810=000010002
只利用8本身来快速判断:它不是0,但是 00001000 & 00000111 = 00000000

int check(int n){int ans=0;while(n){ans++;n=n&(n-1);}return ans;
}

N!中末尾0的个数

(十进制中末尾0个数)
分析:这个问题可以转化成有多少个2和5的配对数。因为2的个数总是大于5的个数,即问题变成求解1——n中所有因子5的个数。
如30!,即是1——30的乘积,与5相关的数字有5,10,15,20,25,30,6个数字,同时25其实贡献了2个5,所以共有7个5。30/5=6. 6/5=1

int zero(int n){int ans=0;while(n){ans+=n/5;n/=5;}return ans;
}

求解N!二进制数字最低位1的位置。

(二进制中末尾0的个数)
分析:我们需要求出计算结果二进制形式的末尾0的个数,这和上面的问题联系在了一起,不过这次需要统计因子2的个数,有多少个2就提升多少位。但是书中给出了一种更加优秀的做法。 h2=N2+N4+N8+N16+
例如求解27!的二进制中最低位1的位置。

2710=110112h=1101+110+11+1=(1000+100+00+1)+(100+10+0)+(10+1)+1=(1000+100+10+1)+(100+10+1)+1=1111+111+1=(100001)+(10001)+(101)+(11)[]=110111

即n!末尾0的个数就是数字本身n-二进制中1的个数。

int two_zero(int n){int ans=0,old=n;while(n){ans++;n=n&(n-1);}return old-ans;
}

寻找最大的k个数

分析:可以用一个特别的数组装下最大的k个数字,然后对于每一个新的数字判断它和其中最小值的关系,如果小弃之,大则替代最小值并更新这个数组。所以这个数组可以是最小堆,也可以是优先队列。

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
int g[1010];
void adjust(int p,int k){int q=p<<1;if(g[q]>g[q+1]) q++;if(q>k)  return ;if(g[p]>g[q]){int t=g[p];  g[p]=g[q];   g[q]=t;adjust(q,k);}
}
int main(){//freopen("cin.txt","r",stdin);int n,k;  // k<1010while(cin>>n>>k){for(int i=1;i<=k;i++) scanf("%d",&g[i]);sort(g+1,g+1+k);for(int i=k+1;i<=n;i++){int t;scanf("%d",&t);if(t>g[1]) {g[1]=t;adjust(1,k);}}for(int i=1;i<=k;i++){printf("%d ",g[i]); }puts("");}return 0;
}

最大公约数问题。

求解两个数的最大公约数
分析:传统的gcd()做法是

int  gcd(int a,int b){return b==0?a:gcd(b,a%b);
}

但是由于有取模的存在,有时会影响效率。
我们知道if (a,b)=c and a=p*a’, b%p!=0 then (a,b)=(a’,b)=c。 即可以取出不相关的部分。
那么,结合计算机的运算特点,可以进行左移和右移提取2。

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
bool odd(LL a){return a&1LL;
}
LL gcd(LL a,LL b){if(a>b) swap(a,b);if(a==1) return 1;if(a==0) return b;if(odd(a) and odd(b)) return gcd(a,b-a);if(!odd(a) and odd(b)) return gcd(a>>1,b);if(odd(a) and !odd(b)) return gcd(a,b>>1);if(!odd(a) and !odd(b)) return gcd(a>>1,b>>1)<<1;
}
int main(){LL a,b;while(cin>>a>>b){cout<<gcd(a,b)<<endl;}return 0;
}

计算斐波那契第n项值

快速计算的方式有:
1. 使用通项公式。
F(n)=55((1+52)n(152)n)

最开始的几项值先递推计算出来并保存,后面n较大的情况可以使用此公式。
但是这种方法有浮点误差。
2. 矩阵快速幂,分治策略。
我们知道

(F(n)F(n1))=(1110)(F(n1)F(n2))

所以,由此可以推算第n项。

快速寻找满足条件的两个数。

能否在一个数组里寻找两个数字,使得他们的和等于一个给定的数。
分析:将数组有序排列,比如从小到大。一个指针放左边,一个指针放右边,双方不断向中间移动,如果大了右指针左移,小了左指针右移。直到找到那个数字。

struct node{int p1, p2;node(int _p1,int _p2){  p1=_p1;  p2=_p2;  };
};
node myfind(int a[],int n,int sum){int i=0,j=n-1;while(i<j){if(a[i]+a[j]==sum) return node(i,j);else if(a[i]+a[j]>sum) j--;else i++;}return node(-1,-1);
}

有一个此问题的拓展应用:http://blog.csdn.net/thearcticocean/article/details/51055538

子数组的最大乘积。

计算长度是N的整数数组中任意N-1个数的组合中最大的一组。
分析:如果没有乘法计算溢出情况出现,可以直接先计算出所有数字的乘积然后针对第i个数字做除法分析即可。
如果存在乘法溢出的情况:
当所有数字的乘积b大于0,当前数字是a[i]–>x, 那么剩下的N-1个数字的乘积y=b/x,函数图像:
这里写图片描述
当b小于0,y=b/x函数图像:
这里写图片描述
还有b等于0的情况,如果数组中存在两个以上的0,那么y就等于0。如果仅仅存在一个0,那么我们可以统计正数和负数的个数分析得出结论。
所以,求解正数的个数,负数的个数,0的个数即可。

求解数组的子数组的最大和。

最大连续子序列问题。
分析:如果从前缀和考虑,那么时间复杂度是n^2
中间过程分析,每一个数字和前面数字的和要么相加要么不加,取最大的那种情况,不断更新答案。dp实现线性n的时间复杂度

int max_sum(int *a,int n){int ans=a[0],temp=a[0];for(int i=1;i<n;i++){temp=max(a[i],temp+a[i]);ans=max(ans,temp);}return ans;
}

子数组的最大和 - 二维

和上面的问题类似,但是二维(注意连续)。
分析:直接枚举计数的效果不理想。因为它和上面的问题有一定的相似性,可以借鉴上面的问题的解法。可以固定上下界然后就变成了一维子数组最大和的问题了。
这里写图片描述

code:

#include <iostream>
#include <cstdio>
using namespace std;
int g[6][6]={
1,-1,5,3,6,-2,
3,-2,7,8,-3,4,
4,2,1,6,-4,7,
5,2,1,0,1,1,
-2,5,3,1,-2,1,
1,2,-1,4,3,0
};
int h[6][6][6];  // h[j][r1][r2]第j列row1到row2的元素的和int main()
{for(int j=0;j<6;j++){for(int r1=0;r1<6;r1++){for(int r2=r1;r2<6;r2++){int temp=0;for(int r=r1;r<=r2;r++){temp+=g[r][j];}h[j][r1][r2]=temp;}}}int ans=-(1<<29);for(int r1=0;r1<6;r1++){   //dpfor(int r2=r1;r2<6;r2++){int temp=h[0][r1][r2];ans=max(ans,temp);for(int j=1;j<6;j++){temp=max(h[j][r1][r2],temp+h[j][r1][r2]);ans=max(ans,temp);}}}printf("%d\n",ans);ans=-(1<<29);for(int i1=0;i1<6;i1++){  // 暴力for(int j1=0;j1<6;j1++){for(int i2=i1;i2<6;i2++){for(int j2=j1;j2<6;j2++){int temp=0;for(int i=i1;i<=i2;i++){for(int j=j1;j<=j2;j++){temp+=g[i][j];}}ans=max(ans,temp);}}}}printf("%d\n",ans);return 0;
}

这篇关于编程之美问题记录——数字之魅1的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/853622

相关文章

从去中心化到智能化:Web3如何与AI共同塑造数字生态

在数字时代的演进中,Web3和人工智能(AI)正成为塑造未来互联网的两大核心力量。Web3的去中心化理念与AI的智能化技术,正相互交织,共同推动数字生态的变革。本文将探讨Web3与AI的融合如何改变数字世界,并展望这一新兴组合如何重塑我们的在线体验。 Web3的去中心化愿景 Web3代表了互联网的第三代发展,它基于去中心化的区块链技术,旨在创建一个开放、透明且用户主导的数字生态。不同于传统

好题——hdu2522(小数问题:求1/n的第一个循环节)

好喜欢这题,第一次做小数问题,一开始真心没思路,然后参考了网上的一些资料。 知识点***********************************无限不循环小数即无理数,不能写作两整数之比*****************************(一开始没想到,小学没学好) 此题1/n肯定是一个有限循环小数,了解这些后就能做此题了。 按照除法的机制,用一个函数表示出来就可以了,代码如下

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

Linux 网络编程 --- 应用层

一、自定义协议和序列化反序列化 代码: 序列化反序列化实现网络版本计算器 二、HTTP协议 1、谈两个简单的预备知识 https://www.baidu.com/ --- 域名 --- 域名解析 --- IP地址 http的端口号为80端口,https的端口号为443 url为统一资源定位符。CSDNhttps://mp.csdn.net/mp_blog/creation/editor

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal

usaco 1.2 Name That Number(数字字母转化)

巧妙的利用code[b[0]-'A'] 将字符ABC...Z转换为数字 需要注意的是重新开一个数组 c [ ] 存储字符串 应人为的在末尾附上 ‘ \ 0 ’ 详见代码: /*ID: who jayLANG: C++TASK: namenum*/#include<stdio.h>#include<string.h>int main(){FILE *fin = fopen (

购买磨轮平衡机时应该注意什么问题和技巧

在购买磨轮平衡机时,您应该注意以下几个关键点: 平衡精度 平衡精度是衡量平衡机性能的核心指标,直接影响到不平衡量的检测与校准的准确性,从而决定磨轮的振动和噪声水平。高精度的平衡机能显著减少振动和噪声,提高磨削加工的精度。 转速范围 宽广的转速范围意味着平衡机能够处理更多种类的磨轮,适应不同的工作条件和规格要求。 振动监测能力 振动监测能力是评估平衡机性能的重要因素。通过传感器实时监

缓存雪崩问题

缓存雪崩是缓存中大量key失效后当高并发到来时导致大量请求到数据库,瞬间耗尽数据库资源,导致数据库无法使用。 解决方案: 1、使用锁进行控制 2、对同一类型信息的key设置不同的过期时间 3、缓存预热 1. 什么是缓存雪崩 缓存雪崩是指在短时间内,大量缓存数据同时失效,导致所有请求直接涌向数据库,瞬间增加数据库的负载压力,可能导致数据库性能下降甚至崩溃。这种情况往往发生在缓存中大量 k

6.1.数据结构-c/c++堆详解下篇(堆排序,TopK问题)

上篇:6.1.数据结构-c/c++模拟实现堆上篇(向下,上调整算法,建堆,增删数据)-CSDN博客 本章重点 1.使用堆来完成堆排序 2.使用堆解决TopK问题 目录 一.堆排序 1.1 思路 1.2 代码 1.3 简单测试 二.TopK问题 2.1 思路(求最小): 2.2 C语言代码(手写堆) 2.3 C++代码(使用优先级队列 priority_queue)

Node.js学习记录(二)

目录 一、express 1、初识express 2、安装express 3、创建并启动web服务器 4、监听 GET&POST 请求、响应内容给客户端 5、获取URL中携带的查询参数 6、获取URL中动态参数 7、静态资源托管 二、工具nodemon 三、express路由 1、express中路由 2、路由的匹配 3、路由模块化 4、路由模块添加前缀 四、中间件