LeetCode 基本四则运算类题目总结

2Add Two Numbers

    题意:给出两个非空的链表代表两个非负数,每位数字再链表中逆序存放。

    思路1:将链表各个数读出来,存到两个int里,最后相加得出答案,再转化为链表返回。问题:数据容易超出范围,遇到这种特地不用整型表示的题应该快速想到这一点。

    思路2:创建链表,直接计算,各位相加,并控制进位,最终每位数都读取完了就返回。题目中特地黑体强调了逆序存放数字,让人很想从链表的最后一个节点开始进行加法(加法都是从个位开始运算),其实不然。因为链表的第一位已经代表了数字的最后一位数。

 ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        int tmp=0;
        ListNode *ret=new ListNode(0);
        ListNode *cur=ret;
        while(1)
        {
            if(l1!=NULL)
            {
                tmp+=l1->val;
                l1=l1->next;
            }
            if(l2!=NULL)
            {
                tmp+=l2->val;
                l2=l2->next;
            }
            cur->val=tmp%10;//修改当前节点的val
            tmp=tmp/10;
            if(l1!=NULL||l2!=NULL||tmp)//最后一位是进位要处理
                cur=(cur->next=new ListNode(0));//创建新节点赋给cur->next,再将cur设置为该新节点
            else
                break;
        }
        return ret;
    }

29Divide Two Integers

题意:实现两个int型数字相除,不能用除法、乘法和取余。

思路:数字的运算常用的基本上也就加减乘除取余了,加法肯定不能用了,只能用减法。通过循环减并记录减了多少次,但当被除数远大于除数的时候随随便便就超时了。所以只能想到位运算,位运算我又不熟,直接看了下discuss果然就是位运算。

算法原理:也是利用减,但是减数是两倍增长,所以不会超时。比如计算18div4,第一次18/4大于1,那把4的bit左移一位(乘2),18/8还是大于1,再左移,直到18/divisor小于1了,说明不够除了,就停止。那关键是获取增长了几次,除数变化规律:1*4、2*4、4*4、8*4,也是两倍增长,所以同样用左移一位的操作来获取。然后不能整除的情况通过最外层的while来处理,为了防止-2147483648的溢出,所以用long long来做计算。

class Solution {
public:
    int divide(int dividend, int divisor) {
          if (!divisor || (dividend == INT_MIN && divisor == -1))
            return INT_MAX;
        int sign = ((dividend < 0) ^ (divisor < 0)) ? -1 : 1;
        long long dvd = labs(dividend);
        long long dvs = labs(divisor);
        int res = 0;
        while (dvd >= dvs) { 
            long long temp = dvs, multiple = 1;
            while (dvd >= (temp << 1)) {
                temp <<= 1;
                multiple <<= 1;
            }
            dvd -= temp;
            res += multiple;
        }
        return sign == 1 ? res : -res;   
    }
};

40Combination Sum II

一个简单的DP,注意对于重复数字的处理。

class Solution {
public:
    vector> combinationSum2(vector& candidates, int target) {
        vector comb;
        vector> ans;
        sort(candidates.begin(),candidates.end());//数组排序,利于查找
        combi(candidates,target,comb,ans,0);
        return ans;
    }
    void combi(vector& candidates,int target,vector &comb,vector> &ans,int begin)
    {
        if(!target)
        {
            ans.push_back(comb);

        }
        for(int i=begin;i

43Multiply Strings

思路:很容易想到乘法的运算,两个数相乘,习惯的去将一个数的各个位去乘以另一个数的整体(123 * 321 打草稿的形式),这里就采用这样的思路。

注意点:

1)长度m和长度n的数相乘,结果最大是m+n位,第一位可能为0,因此第一位需要判断是不是为0。

2)两次循环,保证每个数都能互相乘到。
3)位数越小 下标越大。

4)注意加上某位原来的值以及进位。

class Solution {
public:
    string multiply(string num1, string num2) {
        if(num1=="0" || num2=="0") return "0"; 
        string ans;
        int n1=num1.size(),n2=num2.size(),num=0;
        vector array(n1+n2,0);
        for(int i=n1-1;i>=0;i--)
            for(int j=n2-1;j>=0;j--)
            {
                int p1=i+j,p2=i+j+1; //p1是进位,p2是本位
                num=(num1[i]-'0') * (num2[j]-'0') + array[p2];
                array[p2]=num%10;
                array[p1]+=num/10;
            }
        for(auto i:array)
            if(!(ans.length()==0 && i==0) ) ans.push_back(i+'0');
        return ans;
    }
};

415Add Strings

   大数字的加法。

    分析:从最后一位开始计算,每次都对进位进行处理。由于是加法,所得结果string的长度应该为max(s1.size(),s2.size())+1。

string addStrings(string num1, string num2) {
        int cry=0,n=num1.size(),m=num2.size();
        string ans;
        int len=max(n,m)+1,i=n-1,j=m-1;
        vector ary(len,0);
        for(int i=n-1,j=m-1;i>=0 || j>=0;i--,j--)
        {
            int tmp=0;
            if(i>=0)
                tmp+=num1[i]-'0';
            if(j>=0)
                tmp+=num2[j]-'0';
            if(cry)
                tmp++;
            cry=tmp/10;
            tmp=tmp%10;
            
            ans=char(tmp+'0')+ans;   //注意string加法的顺序,否则逆序
        }
        if(cry)
            ans='1'+ans;//如果存在进位,还要处理。由于是加法最多进1位,所以为'1'
        return ans;     
40 Co
mbination Sum II

你可能感兴趣的:(LeetCode)