leetcode 腾讯50题 1/50 两数相加

每天一道leetcode题目,50天完成腾讯经典50题
题目2 两数相加

题目描述

题目描述
给你两个非空链表,分别表示两个非负整数。表示方法:链表中的每个节点,分别表示整数中的一位数字,顺序从低位至高位。例如:2 -> 4 -> 3 表示342. 请计算两个整数的和,并返回成链表的形式。
数据保证两个整数均不包含前导0(除了0之外),例如:不会出现0023.

样例
输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
解释:342 + 465 = 807.

题解

/**
 * 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) {
        ListNode *res = new ListNode(-1);;   //添加虚拟头结点,简化边界情况的判断
        ListNode *cur = res;//返回链表的当前位
        int carry=0;//判断是否要进位
        while(l1 || l2){//遍历两个链表,直到全部位空
            int n1 = l1?l1->val:0;//链表当前位不存在则为0,否则为当前值
            int n2 = l2?l2->val:0;
            int sum = n1+n2+carry;//两链表相加
            carry=sum/10;//是否进位
            cur->next=new ListNode (sum%10);将计算所得加入返回列表
            cur=cur->next;//各自进入下一个结点
            if(l1) l1=l1->next;
            if(l2) l2=l2->next;
            
        }
        if(carry) cur->next= new ListNode(1);//如果最后的最高为要进位,则加一个1的进位
        return res->next;
    }
};

算法 模拟加法

这道题原理类似于小学学习的加法的原则,从最低位相加,如果大于10则进位,保留个位,依次相加直到最高位便完成了数字的相加,因为所给链表便是数字的逆序,从头至尾遍历便可以得到所求结果
时间复杂度O(n)
知识点
在这道题中,链表存在于结构体当中,因此需要复习一些结构体的知识
结构体是一个由程序员定义的数据类型,可以容纳许多不同的数据值。在过去,面向对象编程的应用尚未普及之前,程序员通常使用这些从逻辑上连接在一起的数据组合到一个单元中。一旦结构体类型被声明并且其数据成员被标识,即可创建该类型的多个变量,就像可以为同一个类创建多个对象一样。

虽然今天结构体较少使用,但知道它们是什么,以及如何使用它们仍然很重要,这并不仅仅是因为可以在较老的程序中遇到它们,还因为在某些情况下,类的实例无法使用,这时必须使用结构体。

声明结构体的方式和声明类的方式大致相同,其区别如下:
使用关键字 struct 而不是关键字 class
尽管结构体可以包含成员函数,但它们很少这样做。所以,通常情况下结构体声明只会声明成员变量。
结构体声明通常不包括 public 或 private 的访问修饰符。
类成员默认情况是私有的,而结构体的成员则默认为 public。程序员通常希望它们保持公开,只需使用默认值即可。

以下是一个结构体声明的示例,该结构体将 5 个变量绑定在一起,保存了员工的工资单数据。这个特殊结构体的名称是 PayRoll。请注意,它以大写字母开头,这和类名使用大写字母开头的约定一样。另外还要注意,与类声明一样,在结构体声明的大括号后面必须有一个分号。

struct PayRoll
{
    int empNumber;
    string name;
    double hours,payRate,grossPay;
};

正如在类的对象被创建之前,类声明不会被实例化一样,结构体声明不会创建任何结构体的实例。本示例中的结构体声明只是告诉编译器PayRoll结构体看起来的样子。它本质上是创建一个名为 PayRoll 的新数据类型。

定义 PayRoll 结构体的变量和定义其他任何变量的方式并无二致,首先列出数据类型,然后是变量名称。以下定义语句创建了 PayRoll 结构体的 3 个变量:

PayRoll deptHead, foreman, associate;

它们每一个都是 PayRoll 结构体的实例,可以被分配和拥有自己的内存,以保存其成员数据。请注意,尽管 3 个结构体变量具有不同的名称,但每个变量都包含具有相同名称的成员

初始化结构体

当定义结构体变量时,可以通过两种方式初始化它:使用初始化列表或构造函数。
初始化列表
初始化结构体变量成员的最简单的方法是使用初始化列表。初始化列表是用于初始化一组内存位置的值列表。列表中的项目用逗号分隔并用大括号括起来。

例如,假设已经声明了以下 Date 结构体:

struct Date
{
    int day, month, year;
};

定义和初始化 Date 变量的方式是:先指定变量名,后接赋值运算符和初始化列表,如下所示:

Date birthday = {23, 8, 1983};

该声明定义 birthday 是一个 Date 结构体的变量,大括号内的值按顺序分配给其成员。所以 birthday 的数据成员已初始化,

也可以仅初始化结构体变量的部分成员。例如,如果仅知道要存储的生日是8月23日, 但不知道年份,则可以按以下方式定义和初始化变量

Date birthday = {23,8};

这里只有 day 和 month 成员被初始化,year 成员未初始化。但是,如果某个结构成员未被初始化,则所有跟在它后面的成员都需要保留为未初始化。使用初始化列表时,C++ 不提供跳过成员的方法。以下语句试图跳过 month 成员的初始化。这是不合法的。

Date birthday = {23,1983}; //非法

还有一点很重要,不能在结构体声明中初始化结构体成员,因为结构体声明只是创建一个新的数据类型,还不存在这种类型的变量。例如,以下声明是非法的:

//非法结构体声明
struct Date
{
    int day = 23,
    month = 8,
    year = 1983;
}

因为结构体声明只声明一个结构体“看起来是什么样子的”,所以不会在内存中创建成员变量。只有通过定义该结构体类型的变量来实例化结构体,才有地方存储初始值。构造函数初始化结构体
虽然初始化列表易于使用,但它有两个缺点:
如果有某个成员未被初始化,那么在这种情况下,跟随在该成员后面的成员都不能初始化。
如果结构体包括任何诸如字符串之类的对象,那么在许多编译器上它都将无法运行。

在这些情况下,可以使用构造函数来初始化结构体成员变量,这和初始化类成员变量是相同的。与类构造函数一样,结构体的构造函数必须是与结构体名称相同的公共成员函数,并且没有返回类型。因为默认情况下,所有结构体成员都是公开的,所以不需要使用关键字 public。

以下是一个名为 Employee 的结构体的声明语句,它包含一个具有两参数的构造函数,以便在创建一个 Employee 变量而不向其传递任何参数时,提供默认值

struct Employee
{
    string name;    // 员工姓名
    int vacationDays,    // 允许的年假
    daysUsed;    //已使用的年假天数
    Employee (string n ="",int d = 0)    // 构造函数
    {
        name = n;
        vacationDays = 10;
        daysUsed = d;
    }
};

访问结构体成员

结构体成员的访问方式与类的公共成员一样,都是使用点运算符。但是,类的数据成员通常是私有的,必须通过函数访问。因为结构数据成员是公共的,所以它们可以被直接访问,并且可以像常规变量一样使用。以下语句即可为前面创建的每个 PayRoll 变量的 empNumber 成员赋值:

deptHead.empNumber = 475;
foreman.empNumber = 897;
associate.empNumber = 729;
cout << deptHead.empNumber << endl;
cout << deptHead.name << endl;
cout << deptHead.hours << endl;
cout << deptHead.payRate << endl;
cout << deptHead.grossPay << endl;
#include <iostream>
#include <iomanip>
#include <string>
using namespace std;
struct PayRoll
{
    int    empNumber; // Employee number
    string name;    // Employee name
    double hours,    // Hours worked
    payRate; // Hourly pay rate
};
int main()
{
    PayRoll employee; // Employee is a PayRoll structure
    double grossPay; // Gross amount the employee earned this week
    cout << "Enter the employee1s number:";
    cin >> employee.empNumber;
    cout << "Enter the employee's name: ";
    cin.ignore();// Skip the '\n' character left in the input buffer
    getline(cin, employee.name);
    cout << "Hours worked this week: ";
    cin >> employee.hours;
    cout << "Employee's hourly pay rate: ";
    cin >> employee.payRate;
   
    // Calculate the employee's gross pay
    grossPay = employee.hours * employee.payRate;
    // Display the results
    cout << "\nHere is the employee1s payroll data:\n";
    cout << "Name:    " << employee.name << endl;
    cout << "Employee number: " << employee.empNumber << endl;
    cout << "Hours worked:    " << employee.hours << endl;
    cout << "Hourly pay rate: " << employee.payRate << endl;
    cout << fixed << showpoint << setprecision(2);
    cout << "Gross pay: $" << grossPay << endl;
    return 0;
}

对于链表操作来说,添加一个虚拟头结点,可以简化边界条件的检查,因此在建立链表时候需要添加虚拟头结点

链表一般需要两个变量,一个是res保存头结点,用来返回整个链表,cur保存当前处理的结点,不停向后扫描添加元素来构造这个链表
结构体成员变量的访问

n1=l1->val

跳转到下一结点

l1=l1->next

动态分配一个结构体

cur->next=new ListNode (sum%10);

将一个元素构造为一个结点并添加在了cur的后面

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值