简单练习

167 阅读10分钟

交换两个变量

#include <iostream>  
  
template<typename T>  
void swapWithoutTemp(T& a, T& b)
{  
    a = a ^ b;  
    b = a ^ b;  
    a = a ^ b;  
}  

十进制vector 输出各自二进制中1个数

std::vector<int> countBitsInVector(const std::vector<int>& decimalVector)
{  
     std::vector<int> bitCounts;  
    bitCounts.reserve(decimalVector.size()); // 预分配空间以提高效率  

    for (int number : decimalVector)
    {  
        // 使用std::bitset来获取二进制表示中1的个数  
        std::bitset<32> binaryRepresentation(number); // 假设整数是32位的  
        bitCounts.push_back(binaryRepresentation.count());  
    }  
    return bitCounts;
}  

std::vector<int> countBitsInVector(const std::vector<int>& decimalVector)
{  
    std::vector<int> bitCounts;  
    bitCounts.reserve(decimalVector.size()); // 预分配空间以提高效率  
  
    for (int number : decimalVector)
    {  
        int count = 0;  
        int n = number;  
        while (n)
        {  
            count += n & 1; // 检查最低位是否为1  
            n >>= 1;        // 右移一位  
        }  
        bitCounts.push_back(count);  
    }  
  
    return bitCounts;  
}  

拷贝字符串std::strcmp

char* copyString(const char* src)
{  
    // 确定原始字符串的长度  
    int length = 0;  
    while (src[length] != '\0')
    {  
        ++length;  
    }  
  
    // 为新字符串分配内存(包括空字符)  
    char* dest = new char[length + 1];  
  
    // 拷贝字符串  
    for (int i = 0; i < length; ++i)
    {  
        dest[i] = src[i];  
    }  
  
    // 添加空字符到字符串的末尾  
    dest[length] = '\0';  
  
    // 返回新字符串  
    return dest;  
}  

void copyString(const char* src, char* dest, int destSize)
{  
    int i = 0;  
    while (src[i] != '\0' && i < destSize - 1)
    {  
        dest[i] = src[i];  
        ++i;  
    }  
    dest[i] = '\0'; // 确保目标字符串以空字符结尾  
}  

逆转字符串

void reverseString(char* str)
{  
    if (str == nullptr)
        return; // 检查空指针  
  
    char* start = str;          // 指向字符串开始  
    char* end = str;            // 初始也指向字符串开始,然后移动到字符串末尾  
  
    // 移动end指针到字符串末尾的前一个字符  
    while (*end != '\0')
    {  
        end++;  
    }  
    end--; // 回退一步,因为end当前指向的是字符串末尾的空字符  
  
    // 逆转字符串  
    while (start < end)
    {  
        // 交换start和end指向的字符  
        char temp = *start;  
        *start = *end;  
        *end = temp;  
  
        // 向中间移动指针  
        start++;  
        end--;  
    }  
}  

topk

std::vector<int> findTopK(const std::vector<int>& nums, int k) 
{  
    std::priority_queue<int, std::vector<int>, std::greater<int>> minHeap; // 小顶堆  
  
    for (int num : nums) 
    {  
        if (minHeap.size() < k)
         {  
            minHeap.push(num);  
        } else if (num > minHeap.top()) 
        {  
            minHeap.pop();  
            minHeap.push(num);  
        }  
    }  
  
    std::vector<int> topK;  
    while (!minHeap.empty())
    {  
        topK.push_back(minHeap.top());  
        minHeap.pop();  
    }  
    std::reverse(topK.begin(), topK.end()); // 因为我们从小顶堆中取出元素是逆序的,所以需要反转  
  
    return topK;  
}  

std::vector<int> findTopK(const std::vector<int>& nums, int k)
{  
    std::multiset<int> ms; // 默认是升序排序  
    std::vector<int> topK;  
  
    for (int num : nums)
    {  
        ms.insert(num);  
        if (ms.size() > k)
        {  
            // 因为是升序排序,所以最小的元素在begin()位置  
            ms.erase(ms.begin());  
        }  
    }  
  
    // 将multiset中的元素复制到vector中  
    for (int num : ms)
    {  
        topK.push_back(num);  
    }  
  
    // 因为multiset是升序排序,如果需要降序结果,可以在这里反转vector  
    std::reverse(topK.begin(), topK.end());  
  
    return topK;  
}  

findKthLargest

//时间复杂度是O(NlogN)
int findKthLargest(const std::vector<int>& nums, int k)
{  
    std::multiset<int> ms(nums.begin(), nums.end()); // 构造multiset并排序  
  
    // 由于multiset是升序排序,第k大的元素将是倒数第(k-1)个元素  
    auto it = ms.rbegin(); // 获取指向最后一个元素的迭代器  
    std::advance(it, k - 1); // 向前移动(k-1)个位置  
  
    return *it; // 返回第k大的元素  
}  

//O(N)
int partition(std::vector<int>& nums, int left, int right)
{  
    int pivot = nums[right];  
    int i = left - 1;  
    for (int j = left; j < right; ++j)
    {  
        if (nums[j] <= pivot)
        {  
            ++i;  
            std::swap(nums[i], nums[j]);  
        }  
    }  
    std::swap(nums[i + 1], nums[right]);  
    return i + 1;  
}  
  
int quickSelect(std::vector<int>& nums, int k, int left, int right)
{  
    if (left == right)
    {  
        return nums[left]; // 只有一个元素时直接返回  
    }  
  
    int pivotIndex = partition(nums, left, right);  
    if (k == pivotIndex)
    {  
        return nums[k]; // 找到第k大的元素  
    }
    else if (k < pivotIndex)
    {  
        return quickSelect(nums, k, left, pivotIndex - 1); // 在左侧分区中查找  
    }
    else
    {  
        return quickSelect(nums, k, pivotIndex + 1, right); // 在右侧分区中查找  
    }  
}  
  
int findKthLargest(std::vector<int>& nums, int k)
{  
    int n = nums.size();  
    // 注意,我们是找第k大的元素,所以要转换成对应的索引  
    // 例如,第1大的元素索引是n-1,第2大的元素索引是n-2,依此类推  
    return quickSelect(nums, n - k, 0, n - 1);  
}  

std::reverse

template<class BidirectionalIterator>  
void reverse(BidirectionalIterator first, BidirectionalIterator last)
{  
    while (first != last && first != --last)
    {  
        std::iter_swap(first++, last);  
    }  
}  

LRU

#include <iostream>  
#include <unordered_map>  
#include <list>  
  
template<typename Key, typename Value>  
class LRUCache
{  
private:  
    int capacity;  
    std::list<std::pair<Key, Value>> cacheList;  
    std::unordered_map<Key, typename std::list<std::pair<Key, Value>>::iterator> cacheMap;  
  
public:  
    LRUCache(int capacity) : capacity(capacity) {}  
  
    Value get(const Key& key)
    {  
        if (cacheMap.find(key) == cacheMap.end())
        {  
            throw std::runtime_error("Key not found");  
        }  
        // Move the accessed item to the front of the list  
        cacheList.splice(cacheList.begin(), cacheList, cacheMap[key]);  
        return cacheMap[key]->second;  
    }  
  
    void put(const Key& key, const Value& value)
    {  
        if (cacheMap.find(key) != cacheMap.end())
        {  
            // Update existing item  
            cacheMap[key]->second = value;  
            // Move the updated item to the front of the list  
            cacheList.splice(cacheList.begin(), cacheList, cacheMap[key]);  
        }
        else
        {  
            // Insert new item  
            if (cacheList.size() >= capacity)
            {  
                // Remove the least recently used item (back of the list)  
                auto it = cacheList.back();  
                cacheMap.erase(it.first);  
                cacheList.pop_back();  
            }  
            cacheList.emplace_front(key, value);  
            cacheMap[key] = cacheList.begin();  
        }  
    }  
};  
  
int main()
{  
    LRUCache<int, std::string> lruCache(3);  
      
    lruCache.put(1, "one");  
    lruCache.put(2, "two");  
    lruCache.put(3, "three");  
      
    std::cout << lruCache.get(1) << std::endl; // Output: one  
    lruCache.put(4, "four"); // Evicts key 2  
      
    try
    {  
        std::cout << lruCache.get(2) << std::endl; // Should throw an exception  
    } catch (const std::runtime_error& e) {  
        std::cout << e.what() << std::endl; // Output: Key not found  
    }  
      
    std::cout << lruCache.get(3) << std::endl; // Output: three  
    std::cout << lruCache.get(4) << std::endl; // Output: four  
      
    return 0;  
}

#include <iostream>  
#include <list>  
#include <unordered_map>  
  
template <typename KeyType, typename ValueType>  
class LRUCache {  
private:  
    int capacity;  
    std::list<std::pair<KeyType, ValueType>> cacheList;  
    std::unordered_map<KeyType, typename std::list<std::pair<KeyType, ValueType>>::iterator> cacheMap;  
  
public:  
    LRUCache(int capacity) : capacity(capacity) {}  
  
    void put(KeyType key, ValueType value)
{  
        auto it = cacheMap.find(key);  
        if (it != cacheMap.end())
        {  
            // Key exists, update the value and move it to the front of the list  
            it->second->second = value;  
            cacheList.splice(cacheList.begin(), cacheList, it->second);  
        }
        else
        {  
            // Key does not exist, insert the new key-value pair  
            if (cacheList.size() == capacity)
            {  
                // Cache is full, remove the least recently used item  
                auto last = cacheList.back();  
                cacheMap.erase(last.first);  
                cacheList.pop_back();  
            }  
            cacheList.emplace_front(key, value);  
            cacheMap[key] = cacheList.begin();  
        }  
    }  
  
    bool get(KeyType key, ValueType &value)
    {  
        auto it = cacheMap.find(key);  
        if (it != cacheMap.end())
        {  
            // Key exists, move it to the front of the list and return the value  
            cacheList.splice(cacheList.begin(), cacheList, it->second);  
            value = it->second->second;  
            return true;  
        }  
        return false; // Key does not exist  
    }  
};  

LRU(Least Recently Used)是一种常见的缓存替换算法,即将最近最少使用的数据进行替换。下面是一个用C++实现LRU缓存的面试题示例:

#include <iostream>  
#include <list>  
#include <unordered_map>  
class LRUCache {
public:
    LRUCache(int capacity) : _capacity(capacity) {}

    int get(int key) {
        auto item = cacheMap.find(key);
        if (item == cacheMap.end()) {
            return -1;
        } else {
            // 使用 splice 将元素移到 list 的前面,表示最近使用
            cacheList.splice(cacheList.begin(), cacheList, item->second);
            return item->second->second; // 使用 iterator 访问 pair 的 value
        }
    }

    void put(int key, int value) {
        auto item = cacheMap.find(key);
        if (item != cacheMap.end()) {
            // 更新现有元素的值,并将其移到 list 的前面
            item->second->second = value;
            cacheList.splice(cacheList.begin(), cacheList, item->second);
        } else {
            if (cacheList.size() == _capacity) {
                // 删除最久未使用的元素(list 的末尾)
                int delKey = cacheList.back().first;
                cacheList.pop_back();
                cacheMap.erase(delKey);
            }
            // 插入新元素到 list 的前面,并更新 map
            cacheList.emplace_front(key, value);
            cacheMap[key] = cacheList.begin();
        }
    }

private:
    int _capacity;
    std::list<std::pair<int, int>> cacheList;
    std::unordered_map<int, std::list<std::pair<int, int>>::iterator> cacheMap;
};

* Your LRUCache object will be instantiated and called as such:
* LRUCache* obj = new LRUCache(capacity);
* int param_1 = obj->get(key);
* obj->put(key,value);


#include <iostream>  
#include <unordered_map>  
#include <list>  
#include <stdexcept>  
  
template<typename K, typename V>  
class LRUCache {  
private:  
    int capacity;  
    std::list<std::pair<K, V>> cacheList;  
    std::unordered_map<K, typename std::list<std::pair<K, V>>::iterator> cacheMap;  
  
public:  
    LRUCache(int capacity) : capacity(capacity) {}  
  
    V get(const K& key) {  
        auto it = cacheMap.find(key);  
        if (it == cacheMap.end()) {  
            throw std::runtime_error("Key not found");  
        }  
        cacheList.splice(cacheList.begin(), cacheList, it->second); // Move to front  
        return it->second->second;  
    }  
  
    void put(const K& key, const V& value) {  
        auto it = cacheMap.find(key);  
        if (it != cacheMap.end()) {  
            cacheList.erase(it->second); // Remove old entry  
        }  
  
        cacheList.emplace_front(key, value); // Insert new entry at front  
        cacheMap[key] = cacheList.begin(); // Update map  
  
        if (cacheList.size() > capacity) {  
            auto last = cacheList.end();  
            --last; // Go to the last element  
            cacheMap.erase(last->first); // Remove from map  
            cacheList.pop_back(); // Remove from list  
        }  
    }  
};  
  
int main() {  
    LRUCache<int, int> lruCache(2);  
  
    lruCache.put(1, 1);  
    lruCache.put(2, 2);  
    std::cout << lruCache.get(1) << std::endl; // 1  
  
    lruCache.put(3, 3); // Evicts key 2  
    try {  
        std::cout << lruCache.get(2) << std::endl; // Throws an exception  
    } catch (const std::exception& e) {  
        std::cout << "Error: " << e.what() << std::endl;  
    }  
  
    lruCache.put(4, 4); // Evicts key 1  
    std::cout << lruCache.get(1) << std::endl; // Throws an exception  
    std::cout << lruCache.get(3) << std::endl; // 3  
    std::cout << lruCache.get(4) << std::endl; // 4  
  
    return 0;  
}

mutex互斥锁

#include <atomic>  
#include <thread>  
#include <iostream>  
#include <chrono>  
#include <this_thread>  
  
class Mutex {  
private:  
    std::atomic_flag flag = ATOMIC_FLAG_INIT;  
  
public:  
    void lock()
{  
        while (flag.test_and_set(std::memory_order_acquire))
    {  
            // 忙等待(自旋锁)  
        }  
    }  
  
    void unlock() {  
        flag.clear(std::memory_order_release);  
    }  
};  

单例模式,线程安全版本

#include <memory>  
#include <mutex>  
  
class Singleton {  
private:  
    static std::shared_ptr<Singleton> instance_;  
    static std::once_flag onceFlag_;  
  
    Singleton() {}  // 私有构造函数,防止外部创建实例  
    Singleton(const Singleton&) = delete;  // 禁止拷贝构造  
    Singleton& operator=(const Singleton&) = delete;  // 禁止拷贝赋值  
  
public:  
    static std::shared_ptr<Singleton> getInstance() {  
        std::call_once(onceFlag_, []() {  
            instance_ = std::shared_ptr<Singleton>(new Singleton());  
        });  
        return instance_;  
    }  
  
    // 其他成员函数...  
};  
  
// 初始化静态成员变量  
std::shared_ptr<Singleton> Singleton::instance_ = nullptr;  
std::once_flag Singleton::onceFlag_;  

翻转链表

class Solution {
public:
    // 定义:输入一个单链表头结点,将该链表反转,返回新的头结点
    ListNode* reverse(ListNode* head) {
        if (head == nullptr || head->next == nullptr) {
            return head;
        }
        ListNode* last = reverse(head->next);
        head->next->next = head;
        head->next = nullptr;
        return last;
    }
};

struct ListNode {  
    int val;  
    ListNode* next;  
    ListNode(int x) : val(x), next(nullptr) {}  
};  
  
ListNode* reverseList(ListNode* head) {  
    ListNode* prev = nullptr;  
    ListNode* curr = head;  
    while (curr != nullptr) {  
        ListNode* nextTemp = curr->next; // 保存下一个节点  
        curr->next = prev; // 翻转当前节点的指针  
        prev = curr; // 将当前节点设为前一个节点  
        curr = nextTemp; // 移动到下一个节点  
    }  
    return prev; // 当原链表遍历完后,prev就变成了新的头结点  
}  
  
void printList(ListNode* head) {  
    ListNode* curr = head;  
    while (curr != nullptr) {  
        std::cout << curr->val << " ";  
        curr = curr->next;  
    }  
    std::cout << std::endl;  
}  

四则运算

#include <iostream>  
#include <stack>  
#include <string>  
#include <sstream>  
#include <cctype>  
  
int precedence(char op) {  
    switch (op) {  
        case '+':  
        case '-':  
            return 1;  
        case '*':  
        case '/':  
            return 2;  
        default:  
            return 0;  
    }  
}  
  
int applyOp(int a, int b, char op) {  
    switch (op) {  
        case '+': return a + b;  
        case '-': return a - b;  
        case '*': return a * b;  
        case '/':   
            if (b != 0) return a / b;  
            else {  
                std::cerr << "Error: Division by zero!" << std::endl;  
                exit(EXIT_FAILURE);  
            }  
        default: return 0;  
    }  
}  
  
int evaluate(const std::string &expression) {  
    std::stack<int> values;  
    std::stack<char> ops;  
  
    for (size_t i = 0; i < expression.length(); ++i) {  
        if (expression[i] == ' ') continue;  
  
        else if (isdigit(expression[i])) {  
            int val = 0;  
            while (i < expression.length() && isdigit(expression[i])) {  
                val = (val * 10) + (expression[i] - '0');  
                i++;  
            }  
            values.push(val);  
            i--; // 因为for循环还会自增,所以这里需要减一  
        }  
  
        else if (expression[i] == '(') {  
            ops.push(expression[i]);  
        }  
  
        else if (expression[i] == ')') {  
            while (!ops.empty() && ops.top() != '(') {  
                int val2 = values.top(); values.pop();  
                int val1 = values.top(); values.pop();  
                char op = ops.top(); ops.pop();  
                values.push(applyOp(val1, val2, op));  
            }  
            if (!ops.empty()) ops.pop(); // 弹出'('  
        }  
  
        else {  
            while (!ops.empty() && precedence(ops.top()) >= precedence(expression[i])) {  
                int val2 = values.top(); values.pop();  
                int val1 = values.top(); values.pop();  
                char op = ops.top(); ops.pop();  
                values.push(applyOp(val1, val2, op));  
            }  
            ops.push(expression[i]);  
        }  
    }  
  
    while (!ops.empty()) {  
        int val2 = values.top(); values.pop();  
        int val1 = values.top(); values.pop();  
        char op = ops.top(); ops.pop();  
        values.push(applyOp(val1, val2, op));  
    }  
  
    return values.top();  
}  

高并发消息队列

在C++中实现一个高并发的消息队列需要考虑线程安全、性能以及可扩展性。以下是一个简化的高并发消息队列的实现示例,它使用了互斥锁(std::mutex)和条件变量(std::condition_variable)来确保线程安全和同步。

#include <queue>  
#include <mutex>  
#include <condition_variable>  
#include <optional>  
  
template <typename T>  
class ConcurrentQueue {  
private:  
    std::queue<T> queue_;  
    std::mutex mutex_;  
    std::condition_variable cond_var_;  
  
public:  
    void push(const T& item) {  
        std::lock_guard<std::mutex> lock(mutex_);  
        queue_.push(item);  
        cond_var_.notify_one(); // 通知等待的线程  
    }  
  
    std::optional<T> pop() {  
        std::unique_lock<std::mutex> lock(mutex_);  
        cond_var_.wait(lock, [this]{ return !queue_.empty(); }); // 等待队列非空  
        T item = queue_.front();  
        queue_.pop();  
        return item;  
    }  
  
    bool empty() const {  
        std::lock_guard<std::mutex> lock(mutex_);  
        return queue_.empty();  
    }  
};  

这个ConcurrentQueue类模板提供了一个线程安全的队列,可以在多个线程之间共享。push方法用于向队列中添加元素,而pop方法用于从队列中取出元素。如果队列为空,pop方法会阻塞调用线程,直到队列中有元素可用。这里有几个关键点需要注意:

  1. 互斥锁(**std::mutex**:用于保护队列数据结构的访问,确保在同一时间只有一个线程可以修改队列。
  2. 条件变量(**std::condition_variable**:用于在队列为空时阻塞pop方法的调用线程,并在有元素被push到队列时唤醒这些线程。
  3. **std::optional<T>**:用于表示pop方法可能返回一个值,也可能在队列为空时返回空值。这里使用std::optional来优雅地处理这种情况,而不是返回一个特殊值或抛出异常。
  4. **std::lock_guard****std::unique_lock**:这些RAII(Resource Acquisition Is Initialization)包装器用于自动管理锁的生命周期,确保在离开作用域时自动释放锁。

请注意,这个实现是一个基本的示例,可能需要根据具体的应用场景进行调整和优化。例如,在高负载下,这个简单的实现可能会成为性能瓶颈。在实际应用中,你可能需要考虑使用更高效的并发数据结构,如无锁队列,或者使用多个队列和工作者线程来分散负载。此外,对于更复杂的多线程环境,你还可能需要考虑如何处理线程的创建、管理和销毁,以及如何处理线程的同步和通信问题。

二叉树序列化反序列化

vector xx ={0 1 2 nullptr nullptr 4 5}
序列化
对于序列化,我们可以使用层序遍历(广度优先搜索,BFS)来遍历二叉树,并将每个节点的值(或表示空节点的特殊值)添加到vector<string>中。

#include <vector>  
#include <string>  
#include <queue>  
#include <sstream>  
  
using namespace std;  
  
// 假设二叉树节点的定义如下  
struct TreeNode {  
    int val;  
    TreeNode* left;  
    TreeNode* right;  
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}  
};  
  
vector<string> serialize(TreeNode* root) {  
    vector<string> result;  
    if (!root) return result; // 如果树为空,则返回空vector  
  
    queue<TreeNode*> q;  
    q.push(root);  
    while (!q.empty()) {  
        TreeNode* node = q.front();  
        q.pop();  
        if (node) {  
            // 将节点值转换为字符串并添加到结果中  
            ostringstream oss;  
            oss << node->val;  
            result.push_back(oss.str());  
            q.push(node->left);  // 将左子节点加入队列  
            q.push(node->right); // 将右子节点加入队列  
        } else {  
            // 使用空字符串表示空节点  
            result.push_back("null");  
        }  
    }  
    return result;  
}  

反序列化
对于反序列化,我们同样可以使用队列来进行层序遍历的重建过程。

TreeNode* deserialize(vector<string>& data) {  
    if (data.empty()) return nullptr; // 如果数据为空,则返回空树  
  
    TreeNode* root = new TreeNode(stoi(data[0])); // 创建根节点  
    queue<TreeNode*> q;  
    q.push(root);  
    int i = 1; // 从第二个元素开始处理,因为第一个元素已经是根节点了  
    while (i < data.size()) {  
        TreeNode* node = q.front();  
        q.pop();  
        if (data[i] != "null") { // 如果不是空节点  
            node->left = new TreeNode(stoi(data[i])); // 创建左子节点  
            q.push(node->left); // 将左子节点加入队列以便后续处理其子节点  
        }  
        i++;  
        if (i < data.size() && data[i] != "null") { // 如果不是空节点且未越界  
            node->right = new TreeNode(stoi(data[i])); // 创建右子节点  
            q.push(node->right); // 将右子节点加入队列以便后续处理其子节点  
        }  
        i++;  
    }  
    return root;  
}  

首先,我们定义一个简单的二叉树节点结构:

struct TreeNode {  
    int val;  
    TreeNode* left;  
    TreeNode* right;  
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}  
};  
序列化
对于序列化,我们可以使用前序遍历(根-左-右)。当遇到nullptr时,我们将其表示为特殊字符串(例如"null")。

#include <vector>  
#include <string>  
#include <sstream>  
  
std::vector<std::string> serialize(TreeNode* root) {  
    std::vector<std::string> result;  
    serializeHelper(root, result);  
    return result;  
}  
  
void serializeHelper(TreeNode* node, std::vector<std::string>& result) {  
    if (node == nullptr) {  
        result.push_back("null");  
        return;  
    }  
    std::stringstream ss;  
    ss << node->val;  
    result.push_back(ss.str());  
    serializeHelper(node->left, result);  
    serializeHelper(node->right, result);  
}  
反序列化
对于反序列化,我们同样使用前序遍历来重建树。

TreeNode* deserialize(const std::vector<std::string>& data, int& index) {  
    if (index >= data.size()) return nullptr;  
    if (data[index] == "null") {  
        index++;  
        return nullptr;  
    }  
    TreeNode* node = new TreeNode(std::stoi(data[index++]));  
    node->left = deserialize(data, index);  
    node->right = deserialize(data, index);  
    return node;  
}  
  
TreeNode* deserialize(const std::vector<std::string>& data) {  
    int index = 0;  
    return deserialize(data, index);  
}  

atoi、std::to_string 函数

isdigit

bool isdigint(char c)
{  
    return (c >= '0' && c <= '9');  
}  

atoi 函数

int myAtoi(const char* str) {  
    int result = 0;  
    int sign = 1;  
    int i = 0;  
  
    // 处理空格  
    while (str[i] == ' ') {  
        i++;  
    }  
  
    // 处理正负号  
    if (str[i] == '-' || str[i] == '+') {  
        sign = (str[i] == '-') ? -1 : 1;  
        i++;  
    }  
  
    // 转换数字  
    while (str[i] >= '0' && str[i] <= '9') {  
        if (result > INT_MAX / 10 || (result == INT_MAX / 10 && str[i] - '0' > INT_MAX % 10)) {  
            return (sign == 1) ? INT_MAX : INT_MIN;  
        }  
        result = result * 10 + (str[i] - '0');  
        i++;  
    }  
  
    return result * sign;  
}  

std::to_string

std::string myToString(int num) {  
    if (num == 0) {  
        return "0";  
    }  
  
    std::string result = "";  
    bool isNegative = false;  
  
    if (num < 0) {  
        isNegative = true;  
        num = -num;  
    }  
  
    while (num > 0) {  
        char digit = '0' + (num % 10);  
        result = digit + result;  
        num /= 10;  
    }  
  
    if (isNegative) {  
        result = '-' + result;  
    }  
  
    return result;  
}

无序链表排序

#include <iostream>  
  
// 链表节点  
struct Node {  
    int data;  
    Node* next;  
  
    Node(int val) : data(val), next(nullptr) {}  
};  
  
// 插入节点并保持链表有序  
void insertSorted(Node*& head, int val) {  
    Node* newNode = new Node(val);  
  
    if (head == nullptr || val < head->data) {  
        newNode->next = head;  
        head = newNode;  
    } else {  
        Node* current = head;  
        while (current->next != nullptr && val > current->next->data) {  
            current = current->next;  
        }  
        newNode->next = current->next;  
        current->next = newNode;  
    }  
}  
  
// 对链表进行排序  
void sortLinkedList(Node*& head) {  
    Node* sortedList = nullptr;  
    Node* current = head;  
  
    while (current != nullptr) {  
        Node* next = current->next;  
        insertSorted(sortedList, current->data);  
        current = next;  
    }  
  
    head = sortedList;  
}  
  
// 打印链表  
void printList(Node* head) {  
    Node* current = head;  
    while (current != nullptr) {  
        std::cout << current->data << " ";  
        current = current->next;  
    }  
    std::cout << std::endl;  
}  

快排

#include <iostream>  
  
// 链表节点  
struct Node {  
    int data;  
    Node* next;  
  
    Node(int val) : data(val), next(nullptr) {}  
};  
  
// 将链表分成两部分,小于基准值的放在左边,大于等于基准值的放在右边  
Node* partition(Node* head, Node* end, Node** newHead, Node** newEnd) {  
    Node* pivot = end;  
    Node* prev = nullptr;  
    Node* current = head;  
    Node* tail = pivot;  
  
    while (current != pivot) {  
        if (current->data < pivot->data) {  
            if (*newHead == nullptr) {  
                *newHead = current;  
            }  
            prev = current;  
            current = current->next;  
        } else {  
            if (prev) {  
                prev->next = current->next;  
            }  
            Node* temp = current->next;  
            current->next = nullptr;  
            tail->next = current;  
            tail = current;  
            current = temp;  
        }  
    }  
  
    if (*newHead == nullptr) {  
        *newHead = pivot;  
    }  
  
    *newEnd = tail;  
  
    return pivot;  
}  
  
// 使用快速排序对链表进行排序  
Node* quickSort(Node* head, Node* end) {  
    if (head == nullptr || head == end) {  
        return head;  
    }  
  
    Node* newHead = nullptr;  
    Node* newEnd = nullptr;  
  
    Node* pivot = partition(head, end, &newHead, &newEnd);  
  
    if (newHead != pivot) {  
        Node* temp = newHead;  
        while (temp->next != pivot) {  
            temp = temp->next;  
        }  
        temp->next = nullptr;  
        newHead = quickSort(newHead, temp);  
        temp = newHead;  
        while (temp->next != nullptr) {  
            temp = temp->next;  
        }  
        temp->next = pivot;  
    }  
  
    pivot->next = quickSort(pivot->next, newEnd);  
  
    return newHead;  
}  

相交链表

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        // p1 指向 A 链表头结点,p2 指向 B 链表头结点
        ListNode *p1 = headA, *p2 = headB;
        while (p1 != p2) {
            // p1 走一步,如果走到 A 链表末尾,转到 B 链表
            if (p1 == nullptr) {
                p1 = headB;
            } else {
                p1 = p1->next;
            }
            // p2 走一步,如果走到 B 链表末尾,转到 A 链表
            if (p2 == nullptr) {
                p2 = headA;
            } else {
                p2 = p2->next;
            }
        }
        return p1;
    }
};

找出一个字符串中最长不重复字串的长度

时间复杂度O(n)

int longestUniqueSubstr(const std::string& str) {  
    int n = str.size();  
    int maxLength = 0;  // 存储最长不重复子串的长度  
    int left = 0, right = 0;  // 滑动窗口的左右指针  
    std::unordered_set<char> charSet;  // 用于存储窗口中的字符  
  
    while (right < n) {  
        // 如果当前字符不在窗口中,则将其添加到窗口中,并尝试扩大窗口  
        if (charSet.find(str[right]) == charSet.end()) {  
            charSet.insert(str[right++]);  
            maxLength = std::max(maxLength, right - left);  
        } else {  // 如果当前字符已经在窗口中,则缩小窗口直到该字符不再在窗口中  
            charSet.erase(str[left++]);  
        }  
    }  
  
    return maxLength;  
}  

斐波那契

递归实现 (fibonacciRecursive):

int fibonacciRecursive(int n) {  
    if (n <= 1) {  
        return n;  
    }  
    return fibonacciRecursive(n - 1) + fibonacciRecursive(n - 2);  
}  
  • 时间复杂度: O(2^n)。这是因为对于每个fibonacciRecursive(n)调用,它会产生两个子调用fibonacciRecursive(n-1)fibonacciRecursive(n-2),这导致了一个二叉树的递归结构,其深度为n,因此总的调用次数大致为2^n。
  • 空间复杂度: O(n)。这是由于递归栈的深度,它随着n的增加而增加。

动态规划实现 (fibonacciDynamic):

int fibonacciDynamic(int n) {  
    if (n <= 1) {  
        return n;  
    }  
    std::vector<int> dp(n + 1);  
    dp[0] = 0;  
    dp[1] = 1;  
    for (int i = 2; i <= n; ++i) {  
        dp[i] = dp[i - 1] + dp[i - 2];  
    }  
    return dp[n];  
}  
  • 时间复杂度: O(n)。这是因为我们只遍历了数列一次,计算了每个位置的值。
  • 空间复杂度: O(n)。这是因为我们使用了一个大小为n+1的数组来存储中间结果。虽然我们可以优化到只使用几个变量来存储前两个斐波那契数,从而将空间复杂度降低到O(1),但在上述实现中,我们保持了O(n)的空间复杂度以展示基本的动态规划思想。
// 使用动态规划实现斐波那契数列,并优化空间复杂度  
int fibonacciOptimized(int n) {  
    if (n <= 1) {  
        return n;  
    }  
      
    int prev = 0; // 前一个斐波那契数  
    int curr = 1; // 当前斐波那契数  
    int next;     // 下一个斐波那契数  
  
    for (int i = 2; i <= n; ++i) {  
        next = prev + curr; // 计算下一个斐波那契数  
        prev = curr;        // 更新前一个斐波那契数  
        curr = next;        // 更新当前斐波那契数  
    }  
  
    return curr; // 返回第n个斐波那契数  
}  

在这个实现中,我们只使用了三个整数变量:prevcurrnext。在每次迭代中,我们计算下一个斐波那契数,并更新prevcurr的值。这样,我们就不需要存储整个数列,从而显著减少了空间使用。这种方法的时间复杂度仍然是O(n),但空间复杂度已经降低到O(1)。

二叉树和最大的层

为了找到二叉树中和最大的层,我们首先需要定义二叉树的结构,并编写一个函数来遍历二叉树的每一层,同时计算每一层的节点和,最后找到和最大的层。

以下是一个简单的C++实现,其中包括了二叉树的定义、层序遍历(使用队列)以及寻找和最大的层的函数。

#include <iostream>  
#include <queue>  
#include <vector>  
#include <climits>  
  
using namespace std;  
  
// 定义二叉树节点  
struct TreeNode
{  
    int val;  
    TreeNode *left;  
    TreeNode *right;  
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}  
};  
  
// 找到二叉树中和最大的层  
int maxLevelSum(TreeNode* root)
{  
    if (!root) return 0; // 如果树为空,则返回0(或适当处理)  
  
    queue<TreeNode*> q;  
    q.push(root);  
    int maxSum = INT_MIN; // 初始化为最小整数  
    int maxLevel = 0;     // 记录最大和的层数  
    int level = 0;        // 当前遍历的层数  
  
    while (!q.empty())
    {  
        int size = q.size();  
        int sum = 0;  
  
        // 遍历当前层的所有节点  
        for (int i = 0; i < size; ++i)
        {  
            TreeNode* node = q.front();  
            q.pop();  
            sum += node->val; // 累加当前层节点的值  
  
            // 将当前节点的左右子节点加入队列(如果存在)  
            if (node->left) q.push(node->left);  
            if (node->right) q.push(node->right);  
        }  
  
        // 更新最大和及对应的层数  
        if (sum > maxSum)
        {  
            maxSum = sum;  
            maxLevel = level;  
        }  
  
        level++; // 进入下一层  
    }  
  
    return maxLevel;  
}  
  
// 测试代码  
int main() {  
    // 构建一个测试用的二叉树  
    //       1  
    //      / \  
    //     2   3  
    //    / \  
    //   4   5  
    TreeNode* root = new TreeNode(1);  
    root->left = new TreeNode(2);  
    root->right = new TreeNode(3);  
    root->left->left = new TreeNode(4);  
    root->left->right = new TreeNode(5);  
  
    cout << "The level with maximum sum is: " << maxLevelSum(root) << endl;  
  
    // 清理内存  
    // 注意:在实际使用中,应编写适当的函数来递归删除树中的所有节点以避免内存泄漏  
  
    return 0;  
}

这个实现中,我们首先定义了一个TreeNode结构来代表二叉树的节点。maxLevelSum函数使用了层序遍历(通过队列)来遍历二叉树的每一层,同时计算每一层的节点和。在遍历过程中,我们记录并更新和最大的层及其对应的和。最后,函数返回和最大的层数。

请注意,在实际应用中,当二叉树不再需要时,应适当删除树中的所有节点以避免内存泄漏。这里为了简化,我们没有包含删除节点的代码。