【002】链表或字符串模拟加法/加一/乘法

链表模拟加法/字符串模拟二进制加法/数组模拟加一操作/打印1到最大的n位数/字符串模拟乘法
============================================
 

Add Two Numbers

两个链表代表两个数字,每个结点的值都是一位数字,单链表逆序存放这两个数字,
构造出一个新的链表,代表这两个链表的和。
链表的尾插法,头结点dummy结点的运用,统一对prev指针的操作,
 
 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
 
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */

class Solution
{
public:
    ListNode *addTwoNumbers(ListNode *l1, ListNode *l2)
    {
         /*头结点,dummy主要是为了保持prev的统一操作*/
        ListNode dummy(- 1);
         int carry =  0;
        ListNode *prev = &dummy;
        ListNode *p1 = l1, *p2 = l2;
         while(p1 !=  NULL || p2 !=  NULL)
        {
             const  int aCur = (p1 ==  NULL) ?  0 : p1->val;
             const  int bCur = (p2 ==  NULL) ?  0 : p2->val;
             const  int value = (aCur + bCur + carry) %  10;
            carry = (aCur + bCur + carry) /  10;
             /*尾插法*/
            prev->next =  new ListNode(value);

            p1 = (p1 ==  NULL) ?  NULL : p1->next;
            p2 = (p2 ==  NULL) ?  NULL : p2->next;
            prev = prev->next;
        }
         if(carry >  0)
        {
            prev->next =  new ListNode(carry);
        }
         return dummy.next;
    }
};

Add Binary

两个字符串模拟二进制的加法,二进制的字符串都是正序存放的,区别于链表模拟加法的题目,
    插入的时候,有头插法和尾插法。这里显然要用到头插法。
 
 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
 
class Solution
{
public:
    string addBinary(string a, string b)
    {
        string result;
         const  int n = a.size() > b.size() ? a.size() : b.size();
         /*反转过来,然后从左到右计算*/
        reverse(a.begin(), a.end());
        reverse(b.begin(), b.end());

         int carry =  0;
         for( int i =  0; i < n; ++i)
        {
             /*有一方,超过了长度就把这一方的设置为0*/
             const  int aCur = i < a.size() ? a[i] -  '0' :  0;
             const  int bCur = i < b.size() ? b[i] -  '0' :  0;
             /*余数*/
             const  int val = (aCur + bCur + carry) %  2;
             /*进位*/
            carry = (aCur + bCur + carry) /  2;

             /*头插法*/
            result.insert(result.begin(), val +  '0');
        }
         if(carry ==  1)
        {
            result.insert(result.begin(),  '1');
        }
         return result;
    }
};
 

Plus One

一个数组代表一个正序的数字,给这个数字做加一操作,返回加一后的结果数组。
carry在循环的外面初始化为true可以统一循环内部的操作。每次都得加上carry。
一旦没有进位这个加一的操作就可以结束了。因为,仅仅是一个加一的操作。
 
 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
 
class Solution
{
public:
     /*most significant digit 最高有效位在左边*/
    vector< int> plusOne(vector< int> &digits)
    {

         int length = digits.size();
         if(length ==  0)
        {
             return digits;
        }
         /*让carry一开始等于true也就模拟了加一操作*/
         bool carry =  true;
         int index = length -  1;
         while(carry && index >=  0)
        {
             /*加1,其实就是加上一个进位*/
            digits[index] += carry;
             if(digits[index] >=  10)
            {
                 /*这种加1的进位,必然导致这个位置变成了0*/
                digits[index] =  0;
                carry =  true;
                index--;
            }
             else
            {
                carry =  false;
                 break;
            }
        }
         if(carry)
        {
             /*如果循环到这里还有进位说明,需要添加一位*/
             /*begin的前面插入1*/
            digits.insert(digits.begin(),  1);
        }
         return digits;
    }
};
 
 
 
面试题12:打印1到最大的n位数
输入n,打印1到最大的n位十进制数
 

方法一,是模拟加法运算的过程,

 

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
 
/*
 * 公共函数
 * 字符串number表示一个数字,数字有若干个0开头
 * 打印出这个数字,并且忽略开头的0
 */

void PrintNumber( char *number)
{
     bool isBeginning0 =  true;
     int nLength = strlen(number);

     for( int i =  0; i < nLength; ++i)
    {
         if(isBeginning0 && number[i] !=  '0')
        {
            isBeginning0 =  false;
        }
         if(!isBeginning0)
        {
            cout << number[i];
        }
    }
    cout <<  "\t";
}

/*
 * 字符串number表示一个数字,在number上增加1
 * 如果做加法溢出,则返回true,否者为false
 */

bool Increment( char *number)
{
     bool isOverflow =  false;
     int carry =  0;
     int nLength = strlen(number);

     for( int i = nLength -  1; i >=  0; i --)
    {
         int nSum = number[i] -  '0' + carry;
         //在循环里面对加1的位置进行了特殊判断
         if(i == nLength -  1)
        {
            nSum ++;
        }

         if(nSum >=  10)
        {
             if(i ==  0)
            {
                isOverflow =  true;
            }
             else
            {
                nSum -=  10;
                carry =  1;
                number[i] =  '0' + nSum;
            }
        }
         else
        {
            number[i] =  '0' + nSum;
             break;
        }
    }
     return isOverflow;
}

/*方法一*/
void Print1ToMaxOfNDigits_1( int n)
{
     if(n <=  0)
    {
         return ;
    }
     //字符串要为'\0'多分配一个空间
     char *number =  new  char[n +  1];
    memset(number,  '0', n);
    number[n] =  '\0';
     //每次都加一然后打印,打印是从1开始的~
     //溢出的时候就是循环终止的时候~
     while(!Increment(number))
    {
        PrintNumber(number);
    }
     delete []number;
}

 

方法二,是n位所有的十进制数其实就是n个从0到9的全排列,也就是说,我么把数字的每一个位都从0到9排列一遍,就得到了所有的十进制数,dfs的感觉

 

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
 
/*
 * 公共函数
 * 字符串number表示一个数字,数字有若干个0开头
 * 打印出这个数字,并且忽略开头的0
 */

void PrintNumber( char *number)
{
     bool isBeginning0 =  true;
     int nLength = strlen(number);

     for( int i =  0; i < nLength; ++i)
    {
         if(isBeginning0 && number[i] !=  '0')
        {
            isBeginning0 =  false;
        }
         if(!isBeginning0)
        {
            cout << number[i];
        }
    }
    cout <<  "\t";
}

//这里的index在控制递归的层数,这里index显然不能大于数字位数范围
void Print1ToMaxOfNDigitsRecursively( char *number,  int length,  int index)
{
     if(index == length -  1)
    {
        PrintNumber(number);
         return ;
    }
     //每一个位置上都可能是0...9
     for( int i =  0; i <  10; ++i)
    {
         //index在递归的上一层已经放过数字了
        number[index +  1] = i +  '0';
        Print1ToMaxOfNDigitsRecursively(number, length, index +  1);
    }
}

/*方法二*/
void Print1ToMaxOfNDigits_2( int n)
{
     if(n <=  0)
    {
         return ;
    }
     char *number =  new  char[n +  1];
    number[n] =  '\0';
     //每一个位置上都可能是0...9
     for( int i =  0; i <  10; ++i)
    {
        number[ 0] = i +  '0';
        Print1ToMaxOfNDigitsRecursively(number, n,  0);
    }
     delete[] number;
}

 

 

Multiply Strings

Given two numbers represented as strings, return multiplication of the numbers as a string.

Note: The numbers can be arbitrarily large and are non-negative.

把字符转换成数字,然后对这些数字做乘法,然后做进位操作,然后在转换成字符,把这些字符拼接成字符串

 
 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
 
class Solution
{
public:
    string multiply(string num1, string num2)
    {
         /*因为仅仅说是非负的,可能为0*/
         if(num1 ==  "0" || num2 ==  "0")
        {
             return  "0";
        }

         int l1 = num1.length(), l2 = num2.length();

         int *n1 =  new  int[l1];
         int *n2 =  new  int[l2];
         int *res =  new  int[l1 + l2];
         /*res数组必须初始化为0*/
        memset(res,  0sizeof( int) * (l1 + l2));

         for( int i =  0; i < l1; ++i)
        {
            n1[i] = num1[i] -  '0';
        }
         for( int i =  0; i < l2; ++i)
        {
            n2[i] = num2[i] -  '0';
        }

         /*res暂时不存计算结果,为之后的进位操作做准备
         * 1 ... l1+l2-1
         */

         for( int i =  0; i < l1; ++i)
        {
             for ( int j =  0; j < l2; ++j)
            {
                res[i + j +  1] += n1[i] * n2[j];
            }
        }
         /*个位数在最右边 (l1 - 1) + (l2 - 1) + 1*/
        string ss =  "";
         for ( int k = l1 + l2 -  1; k >=  0; --k)
        {
             if(k >  0)
            {
                res[k -  1] += res[k] /  10;
            }
            res[k] %=  10;
             /*头插法*/
            ss =  char(res[k] +  '0') + ss;
        }
         /*res[1] / 10进位给res[0],这个进位可能为0*/
        ss = ss[ 0] ==  '0' ? ss.substr( 1) : ss;
         return ss;
    }
};

转载于:https://www.cnblogs.com/codemylife/p/3779267.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值