数据结构(二)

1.两数之和

给出一个整型数组 numbers 和一个目标值 target,请在数组中找出两个加起来等于目标值的数的下标,返回的下标按升序排列。(注:返回的数组下标从1开始算起,保证target一定可以由数组里面2个数字相加得到)

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map<int, int> hashtable; 
        for (int i = 0; i < nums.size(); ++i) { 
            auto it = hashtable.find(target - nums[i]);
            //在哈希表内查值,是否有target-nums[i]的值
            if (it != hashtable.end()) {
                return {it->second, i};//first表示键值,second表示下标值
            }
            hashtable[nums[i]] = i;//将nums[i]加入到哈希表中
        }
        return {};
    }
};

注释:

①.首先建立一个无序的哈希表

②.在哈希表内查值,是否有target-nums[i]的值

对于这个数组,数组元素2例:输入:nums = [2,7,11,15], target = 9

输出:[0,1]

解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。

2,7,11,15就是key 键值,数组的下表0,1,2,3就

是值。遍历这个数组,对于第一个元素,target-nums[i]=9-2=7,在数组中寻找键值

为7的元素的值(下标),键值为7的元素他的值为1.

③.如果他没有在哈希表的尾部,则返回他的值

④.将找到的键值加入哈希表中

哈希表:

使用find,返回的是被查找元素的位置,没有则返回map.end()

使用count,返回的是被查找元素的个数。如果有,返回1;否则,返回0。注意,map中不存在相同元素,所以返回值只能是1或0。

2.合并两个排序的链表

输入两个递增的链表,单个链表的长度为n,合并这两个链表并使新链表中的节点仍然是递增排序的。

class Solution {
public:
    ListNode* Merge(ListNode* pHead1, ListNode* pHead2) {
        //一个已经为空了,直接返回另一个
        if(pHead1 == NULL)
            return pHead2;
        if(pHead2 == NULL)
            return pHead1;
        //加一个表头
        ListNode* head = new ListNode(0);
        ListNode* cur = head;
        //两个链表都要不为空
        while(pHead1 && pHead2){
            //取较小值的节点
            if(pHead1->val <= pHead2->val){
                cur->next = pHead1;
                //只移动取值的指针
                pHead1 = pHead1->next;
            }else{
                cur->next = pHead2;
                //只移动取值的指针
                pHead2 = pHead2->next;
            }
            //指针后移
            cur = cur->next;
        }
        //哪个链表还有剩,直接连在后面
        if(pHead1)
            cur->next = pHead1;
        else
            cur->next = pHead2;
        //返回值去掉表头
        return head->next;
    }
};

注释:共定义三个指针,pHead1用于链表1,pHead2用于链表2,cur用于排序时的新链表,需要初始化一个空结点,初始值为0,指针指向为head。

代码分三块:

①任一链表为空的情况;

②大小比较部分,小的接在cur->next后面;

③剩余的没有比较完的,接在cur->next后面。

3.返回倒数第k个节点

实现一种算法,找出单向链表中倒数第 k 个节点。返回该节点的值。

class Solution {
public:
    int kthToLast(ListNode* head, int k) {
        ListNode* first = head;
        ListNode* second = head;
        while(k-- > 0){
            first = first->next;
        }
        while(first != nullptr){
            first = first->next;
            second = second->next;
        }
        return second->val;

    }
};

注释:采用双指针,first指针先走k步,然后两指针一块走。

4.判断链表是否成环

给你一个链表的头节点 head ,判断链表中是否有环。

class Solution {
public:
    bool hasCycle(ListNode *head) {
        if(head == nullptr || head->next == nullptr){
            return false;
        }
        ListNode* slow = head;
        ListNode* fast = head->next;
        while(slow != fast){
            if(fast == nullptr || fast->next == nullptr){
                return false;
            }
            slow = slow->next;
            fast = fast->next->next;
        }
        return true;
    }
};

注释:

①判断头节点是否为空

②定义快慢指针

③while中定义成环条件,slow != fast,fast指针或fast->next为空说明不成环,快慢指针向前走

5.删除中间节点

若链表中的某个节点,既不是链表头节点,也不是链表尾节点,则称其为该链表的「中间节点」。

假定已知链表的某一个中间节点,请实现一种算法,将该节点从链表中删除。

class Solution {
public:
    void deleteNode(ListNode* node) {
        node->val = node->next->val;//将node节点下一个节点的值复制给node
        node->next = node->next->next;//将node的next指针跳过已复制的节点
    }
};

6.链表的中间节点

给定一个头结点为 head 的非空单链表,返回链表的中间结点。

如果有两个中间结点,则返回第二个中间结点。

class Solution {
public:
    ListNode* middleNode(ListNode* head) {
        ListNode* slow = head;
        ListNode* fast = head;
        while(fast != NULL && fast->next != NULL){
            slow = slow->next;
            fast = fast->next->next;
        }
        return slow;
    }
};

注释:使用快慢指针,循环条件是fast指针不为空且fast的next指针也不为空。

7.不同路径

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。

机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。

问总共有多少条不同的路径?

class Solution {
public:
    int uniquePaths(int m, int n) {
        vector<vector<int>> v(m, vector<int>(n));
        for(int i = 0; i < m; ++i){
            v[i][0] = 1;
        }
        for(int j = 0; j < n; ++j){
            v[0][j] = 1;
        }
        for(int i =  1; i < m; ++i){
            for(int j = 1; j < n; ++j){
                v[i][j] = v[i - 1][j] + v[i][j - 1];//状态转移方程
            }
        }
        return v[m - 1][n - 1];
    } 
};

注释:

①走到每一格的路径数量等于上面格子路径数量和左边格子路径数量之和,即v(x,y)=v(x - 1, y) + v(x, y - 1),即是状态转移方程。

②vector<vector<int>> v(m, vector<int>(n));

定义了一个vector容器,元素类型为vector<int>,初始化包含m个vector<int>对象,每个对象都是一个新创立的vector<int>对象拷贝,而这个新创立的vector<int>对象被初始化包含n个0。

从结果上看,类似于创建了一个mxn的二维数组,而且可以通过v[i][j]的方式来访问元素。(vector支持下标访问元素)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值