[问题1]用+-*等运算实现整数的除法
用逆运算很容易求解,关键是算法复杂度。可以预设一些乘数,例如1,2,4,8,16,32(也就是2^0,2^1,...2^n),然后我们用减法不断地判断区间(折半),例如
20/3等于多少? 答案是6。那么求解过程是:
(1)先找出2^n的n的区间,3*2^2 < 20 < 3*2^3,所以20=3*2^2 + 8,商=2
(2)余数部分是8,继续判断 3*2^1 < 8 < 3*2^2 所以 8=3*2^1 + 2,商=1
(3)余数2小于除数3,不再运算。所以上述算法求出的20/3= 2^2(第一次商=2) +2^1(第二次商=1) = 6即为所求。
算法复杂度为O(lglgN)。
- import java.util.*;
- public class MyMain {
- public static void main(String[] args) {
- ArrayList<Integer> result=new ArrayList<Integer>();
- long a=1000;//被除数
- final long b=7;//除数
- int exp=32;//初始指数
- long mid=1<<exp;
- while(a>b){
- if(a<b*mid){
- mid>>=1;
- --exp;
- }else{
- a-=(b*mid);
- result.add(exp);
- }
- }
- int r=0;
- for(Iterator<Integer> it=result.iterator();it.hasNext();){
- r+=1<<(it.next().intValue());
- }
- System.out.println("r="+r);
- }
- }
import java.util.*;
public class MyMain {
public static void main(String[] args) {
ArrayList<Integer> result=new ArrayList<Integer>();
long a=1000;//被除数
final long b=7;//除数
int exp=32;//初始指数
long mid=1<<exp;
while(a>b){
if(a<b*mid){
mid>>=1;
--exp;
}else{
a-=(b*mid);
result.add(exp);
}
}
int r=0;
for(Iterator<Integer> it=result.iterator();it.hasNext();){
r+=1<<(it.next().intValue());
}
System.out.println("r="+r);
}
}
答案是1000/7=142。刚才说过,指数匹配的过程可以用折半查找来优化,C++实现的版本如下:
- #include<list>
- using namespace std;
- int main(){
- list<int> li;
- int a = 1000;//被除数
- const int b = 7;//除数
- int exp=8;//初始指数
- int begin=0;
- int end=exp;
- int mid=(begin+end)/2;
- while(true){
- if(a<b*(1<<mid)){
- int newMid=(begin+mid)/2;
- end=mid;
- mid=newMid;
- }else if(a>b*(1<<(mid+1))){
- int newMid=(mid+end)/2;
- begin=mid;
- mid=newMid;
- }else{
- a-=b*(1<<mid);
- li.push_back(mid);
- if(a<b)break;
- begin=0;
- end=exp;
- mid=(begin+end)/2;
- }
- }
- int r=0;
- for(auto it=li.begin();it!=li.end();++it){
- r+=1<<*it;
- }
- printf("%d\n",r);
- return 0;
- }
#include<list>
using namespace std;
int main(){
list<int> li;
int a = 1000;//被除数
const int b = 7;//除数
int exp=8;//初始指数
int begin=0;
int end=exp;
int mid=(begin+end)/2;
while(true){
if(a<b*(1<<mid)){
int newMid=(begin+mid)/2;
end=mid;
mid=newMid;
}else if(a>b*(1<<(mid+1))){
int newMid=(mid+end)/2;
begin=mid;
mid=newMid;
}else{
a-=b*(1<<mid);
li.push_back(mid);
if(a<b)break;
begin=0;
end=exp;
mid=(begin+end)/2;
}
}
int r=0;
for(auto it=li.begin();it!=li.end();++it){
r+=1<<*it;
}
printf("%d\n",r);
return 0;
}
[问题2]有一个数列,求其中拥有最大和的子序列(子序列是连续的元素组成的)
这个问题是这样的: 如果是全正数,显然是全体加和。如果全是负数,一个都不取就行了,最大和没有意义。因此测试数据采用有正有负的数列。例如{-4,3,-5,7,1,-2,3,-1}最大和子序列是7,1,-2,3,和=9。
- public class MyMain {
- public static void main(String[] args) {
- int data[]={-4,3,-5,7,1,-2,3,-1};
- int best=0;
- int startPos=0;
- int endPos=0;
- for(int i=0;i<data.length;++i){
- int sum=0;//每次计算从i开始的所有子序列的最大和
- for(int j=i;j<data.length;++j){
- int calc=sum+data[j];
- if(calc<0)break;//算负了,跳到外层循环
- sum=calc;
- if(sum>best){
- best=sum;
- startPos=i;
- endPos=j;
- }
- }
- }
- System.out.println("best="+best+",start="+startPos+",endPos="+endPos);
- }
- }
public class MyMain {
public static void main(String[] args) {
int data[]={-4,3,-5,7,1,-2,3,-1};
int best=0;
int startPos=0;
int endPos=0;
for(int i=0;i<data.length;++i){
int sum=0;//每次计算从i开始的所有子序列的最大和
for(int j=i;j<data.length;++j){
int calc=sum+data[j];
if(calc<0)break;//算负了,跳到外层循环
sum=calc;
if(sum>best){
best=sum;
startPos=i;
endPos=j;
}
}
}
System.out.println("best="+best+",start="+startPos+",endPos="+endPos);
}
}