搬砖小技巧|二分&双指针

今天看到两道很有意思的题目:
题一:

给定两个整数 a 和 b ,求它们的除法的商 a/b ,要求不得使用乘号 '*'、除号 '/' 以及求余符号 '%' 。

整数除法的结果应当截去(truncate)其小数部分,例如:truncate(8.345) = 8 以及 truncate(-2.7335) = -2

乍一看,算除法不能用除法这不是来找茬么。

下面贴出思路:

以a = 36, b = 7为例。由于不能用乘除法,这里只能用加法。最简单思路是从0开始不断加7,看什么时候结果大于36。但是a很大,b很小时,这个方法太慢了。

我们这样改进:

令temp = b = 7, re = 1;此时36>7,说明a里至少有1(re)个b;

令temp = temp+temp = 14, re = re+re = 2;此时36>14, 说明a里至少有2(re)个b;

令temp = temp+temp = 28, re = re+re = 4;此时36>28, 说明a里至少有4(re)个b;

令temp = temp+temp = 56, re = re+re = 8;此时36<56, 说明a里没有有8(re)个b;

因此a里b的数量大于等于4,小于8。我们令result = 4, 令a = a-28 = 12.再重复上述过程:

令temp = b = 7, re = 1;此时12>7,说明(新)a里至少有1(re)个b;

令temp = temp+temp = 14, re = re+re = 2;此时12 <14, 说明(新)a里没有2(re)个b;

因此(新)a里有1个b。令result=result+1,令a = a-7=5。此时a已经小于b,程序停止。此时的result=5就是我们要的结果。

再贴出核心思路代码:

int divide(int a, int b)
 {
 	int flag=1, result = 0;
//先将两数均变为正数,flag表示结果正负
 	if(a < 0)
 	{
 		a = -a;
 		flag = -flag;
	}
	if(b < 0)
	{
		b = -b;
		flag = -flag;
	}

	while(a >= b)
	{
		int temp = b;
		int re = 1;
		while(a >= temp+temp)
		{
			temp += temp;
			re += re;
		}
		result += re;
		a -= temp;
	}
	if(flag >0) return result;
	else return -result;
 }
 

题二:

第二道题也很有意思,题目实现很简单,要想在限制时间内通过则需要思考一下。

给你一个包含 n 个整数的数组 ,判断 数组 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。

 暴力求解当然能解决,但肯定超时。我一开始的思路是两两求和,再剩余元素中找和的相反数,需要用到一个映射map。实际操作中发现会重复取到三元组,又用了如下方法删去重复。

sort(result.begin(), result.end());
result.erase(unique(result.begin(), result.end()), result.end());

几个测例过了,但仍然超时,不得已又看了评论区思路。

先贴上评论区打油诗一首(出自用户iiame):

一顿操作猛如虎,点击提交超时了。

二话不说翻题解,评论区里全人才。

反反复复终得道,再次尝试却报错。

行行检查字字改,击败用户百分五。

有一个双指针的思路我举得不错,直接贴出根据该思路写的代码:

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
       sort(nums.begin(), nums.end());
       vector<vector<int>> result;
       for(int c = 0; c<nums.size()-2;)
       {
           for(int a=c+1, b = nums.size()-1;a<b;)
           {
               if(nums[a]+nums[b]>-nums[c])
               {
                   //do{b--;} while(a<b && nums[b]==nums[b+1]);
                   b--;
               }
               else if(nums[a]+nums[b]<-nums[c])
               {
                   //do{a++;} while(a<b && nums[a]==nums[a-1]);
                   a++;
               }
               else
               {
                   vector<int> r = {nums[c], nums[a], nums[b]};
                   result.push_back(r);
                   do{a++;} while(a<b && nums[a]==nums[a-1]);
                   do{b--;} while(a<b && nums[b]==nums[b+1]);
               }
           }
           do{c++;} while(c<nums.size()-2 && nums[c]==nums[c-1]);
       }
       return result;
    }
};

相同思路,可以解决以下问题:

给你一个长度为 n 的整数数组和 一个目标值。请你从该数组中选出三个整数,使它们的和与目标值最接近。

请返回这三个数的和。(假定每组输入只存在恰好一个解。)

 直接贴出代码:

class Solution {
public:
    int threeSumClosest(vector<int>& nums, int target) {
        int result = 100000;
        sort(nums.begin(), nums.end());
        for(int i=0;i<nums.size();i++)
        {
            int tarn = target - nums[i];
            for(int a = i+1, b = nums.size()-1; a < b;)
            {
                if(abs(tarn - (nums[a]+nums[b])) < abs(result - target)) {result = nums[i] + nums[a] + nums[b];}
                if(nums[a]+nums[b] > tarn) b--;
                else if(nums[a]+nums[b] < tarn) a++;
                else return target;
            }
        }
        return result;
    }
};

说明:以上题目均来自于leetcode,解决思路借鉴了评论区,但代码均为原创手敲。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

鲸鲸爱柠檬

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

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

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

打赏作者

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

抵扣说明:

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

余额充值