基础题

反转链表

/******************************************************************************
* File:             reverse_list.cpp
*
* Author:           yychi  
* Created:          2022-12-29 20:35 
* Description:      Reverse a linked list.
*****************************************************************************/
#include <cstdio>
#include <time.h>
#include <stdlib.h>
 
 
struct ListNode
{
    ListNode(int _val): val(_val), next(nullptr) {}
    int val;
    ListNode* next;
    void print()
    {
        printf("%d", val);
        if (next)
        {
            printf("->");
            next->print();
        }
        else
        {
            printf("\n");
        }
    }
};
 
 
ListNode* ReverseList(ListNode* head)
{ // O(n) time, O(1) space
    if (!head || !head->next) return head;
    ListNode *a = head, *b = head->next;
    while (b)
    {
        ListNode* tmp = b->next;
        b->next = a;
        a = b;
        b = tmp;
    }
    head->next = nullptr;
    return a; 
}
 
 
ListNode* ReverseListRecursive(ListNode* head)
{ // O(n^2) time
    if (!head || !head->next) return head;
    ListNode* ret = ReverseListRecursive(head->next);
    ListNode* p = ret;
    while (p->next)
    {
        p = p->next;
    }
    p->next = head;
    head->next = nullptr;
    return ret;
} // 如果每一步返回尾后指针,走到底的时候记录下原来那个最末尾指针作为返回值(反转后指针的头),就可以把复杂度降下来啦
 
// update 2024/9/25, 返回尾后指针的版本
struct ReverseListFunctor
{
    ListNode* head;
    ListNode* operator()(ListNode* head)
    {
        // base case
        if (!head || !head->next) return head;
        helper(head)->next = nullptr;
        return this->head;
    };
 
    // give the last element of the reversed list
    ListNode* helper(ListNode* head)
    {
        if (head && !head->next)
        {
            this->head = head;
            return head;
        }
        helper(head->next)->next = head;
        return head;
    }
};
 
 
int main()
{
    srand(time(NULL));
    ListNode head(345);
    ListNode* p = &head;
    for (int i = 0; i < 10; ++i)
    {
        int x = rand() % 99;
        // auto node = ListNode(x);
        // p->next = &node;
        p->next = new ListNode(x);
        p = p->next;
    }
    head.print();
 
    printf("recursive way:\n");
    ListNode* rhead = ReverseListRecursive(&head);
    rhead->print();
 
    printf("iterative way:\n");
    ReverseList(rhead)->print();
    return 0;
}

合并有序链表

猛击此处获取live demo.

/******************************************************************************
* File:             lisuan.cpp
*
* Author:           yychi  
* Created:          2022-08-10 22:44 
* Description:      merge two sorted link list, iteratively and recursively.
*****************************************************************************/
#include <stdio.h>
 
 
struct ListNode
{
    ListNode(int _val): val(_val), next(nullptr) {}
    int val;
    ListNode* next;
 
    void print()
    {
        printf("%d", val);
        if (next)
        {
            printf("->");
            next->print();
        }
        else
        {
            printf("\n");
        }
    }
};
 
 
ListNode* MergeLinkList(ListNode* a, ListNode* b)
{
    // two base cases.
    if (!a) return b;
    if (!b) return a;
 
    ListNode ret(0);
    ret.next = a;
 
    ListNode* pa = &ret;
    for (; a && b; )
    {
        if (a->val <= b->val)
        {
            pa = a;
            a = a->next;
        }
        else
        {
            ListNode* b_nex = b->next;
            pa->next = b;
            b->next = a;
            pa = b;
            b = b_nex;
        }
    }
 
    // append tail
    if (!a && b) pa->next = b;
    return ret.next;
}
 
 
/**
 * Recursive way.
 */
ListNode* MergeLinkListRecursive(ListNode* a, ListNode* b)
{
    if (!a) return b;
    if (!b) return a;
 
    if (a->val <= b->val)
    {
        a->next = MergeLinkListRecursive(a->next, b);
        return a;
    }
    else
    {
        b->next = MergeLinkListRecursive(a, b->next);
        return b;
    }
}
 
 
// test
int main()
{
    ListNode* a = new ListNode(3);
    ListNode* pa = a;
    pa->next = new ListNode(5);
    pa = pa->next;
    pa->next = new ListNode(19);
    pa = pa->next;
    pa->next = new ListNode(21);
    pa = pa->next;
    pa->next = new ListNode(30);
 
    ListNode* b = new ListNode(1);
    ListNode* pb = b;
    pb->next = new ListNode(4);
    pb = pb->next;
    pb->next = new ListNode(6);
    pb = pb->next;
    pb->next = new ListNode(8);
    pb = pb->next;
    pb->next = new ListNode(10);
    pb = pb->next;
    pb->next = new ListNode(45);
 
    // print a, b
    a->print();
    b->print();
 
    printf("before call a=%p, b=%p, a.next=%p, b.next=%p\n", a, b, a->next, b->next);
    MergeLinkList(a, b)->print();
    printf("after call a=%p, b=%p, a.next=%p, b.next=%p\n", a, b, a->next, b->next);
    // MergeLinkListRecursive(a, b)->print();
    return 0;
}

最大子数组的和

see: https://leetcode.com/problems/maximum-subarray/description/

从头开始累加,关键是什么时候丢弃当前的累加进度,重新开始。答:当累加和小于当前元素的时候,不如丢弃累加和,直接从当前元素再开始累加。

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int ret = INT_MIN, sum = 0;
        for (int e : nums)
        {
            sum = max(sum+e, e);
            ret = max(ret, sum);
        }
        return ret;
    }
};

最大子数组的乘积

see: https://leetcode.com/problems/maximum-product-subarray/description/

和上面的问题类似,但是这里多了负负得正的情况,所以处理起来比较麻烦。关键点在于:每次遍历,记录当前最大乘积和当前最小乘积(因为最小乘积可能呈乘一个负数翻正从而比最大乘积更大)。然后更新全局最大乘积。

class Solution {
public:
    int maxProduct(vector<int>& nums) {
        int ret = INT_MIN;
        int pmin = 1, pmax = 1, n, m;
        for (auto e : nums)
        {
            n = pmin * e;
            m = pmax * e;
            pmin = min({n, m, e});
            pmax = max({n, m, e});
            ret = max(pmax, ret);
        }
        return ret;
    }
};

字符串相乘

see: https://leetcode.com/problems/multiply-strings/description/

本质上是模拟竖式相乘,直接模拟即可,需要注意细节。

class Solution {
public:
 
/**
 * 考虑竖式乘法中,单个位置上的结果累加,考虑循环进位。
 */
void add_by_carrier(string& o, size_t index, int value)
{
    if (value <= 0 || index >= o.size()) return;
    int p = value + (o[index] - '0');
    o[index] = '0' + (p % 10);
    add_by_carrier(o, index+1, p/10);
}
 
string multiply(string num1, string num2)
{
    std::reverse(num1.begin(), num1.end());
    std::reverse(num2.begin(), num2.end());
    string ret(num1.size() + num2.size(), '0');
 
    for (size_t i = 0; i < num1.size(); ++i)
    {
        int p1 = num1[i] - '0';
        for (size_t j = 0; j < num2.size(); ++j)
        {
            add_by_carrier(ret, i+j, p1 * (num2[j]-'0'));
        }
    }
    while (ret.size() > 1 && ret.back() == '0')
        ret.pop_back();
 
    std::reverse(ret.begin(), ret.end());
    return ret;
}
 
};

二分查找

leetcode cn #704 https://leetcode.cn/problems/binary-search/description/

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target  ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1

#define GREEDY true
 
class Solution {
public:
    int search(vector<int>& nums, int target) {
        return my_binary_search(nums, target);
    }
 
 
int my_binary_search(const vector<int>& arr, int target)
{
    int beg = 0, end = arr.size(), mid = 0;
    while (beg + 1 < end)
    {
        mid = (beg + end) / 2;
        if (target == arr[mid])
        {
#if GREEDY
            // in case of the array is not monotone increasing (i.e., it contains
            // some duplicated elements), we want the maximal index `i' such that
            // arr[i] = target.
            beg = mid;
#else
            return mid;
#endif
        }
        if (target < arr[mid])
        {
            end = mid;
        }
        if (target > arr[mid])
        {
            beg = mid;
        }
    }
    if (target == arr[beg]) return beg;
    return -1;
}
};