Leetcode上的各种“Reverse”

A. 单链表整体的逆转

题目链接:https://leetcode.com/problems/reverse-linked-list/

其实做法挺简单的,就是将每个节点的next指针指向原来链表中的上一个就好了,注意对NULL的处理。

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode *last = NULL, *now = head;

        while (now != NULL) {
            ListNode* nextOne = now->next;
            now->next = last;
            last = now;
            now = nextOne;
        }

        return last;
    }
};

B. 单链表的部分逆转

即旋转链表第m个节点到第n个节点之间的部分,逆转部分跟A的原理一样,不过要处理好左右,以及NULL的情况。
原题链接:https://leetcode.com/problems/reverse-linked-list-ii/

#include <stdio.h>
#include <assert.h>

struct ListNode {
    int val;
    ListNode *next;
    ListNode(int x): val(x), next(NULL) {}

    void append(int x) {
        assert(this != NULL);
        ListNode* now = this;
        while (now->next != NULL)
            now = now->next;
        now->next = new ListNode(x);
    }

    void print() {
        ListNode* now = this;
        while (now != NULL) {
            printf("%d ", now->val);
            now = now->next;
        }
        printf("\n");
    }
};

class Solution {
public:
    ListNode* reverseBetween(ListNode* head, int m, int n) {
        if (m == n)
            return head;

        ListNode *left = NULL, *right = NULL;
        ListNode *left_pre = NULL, *right_next = NULL;
        ListNode *now = head, *last = NULL;

        for (int i = 1; now != NULL; ++i) {
            if (i == m-1)
                left_pre = now;
            else if (i == m) 
                left = last = now;
            else if (i == n)
                right = now;
            else if (i > n) {
                right_next = now;
                break;
            }

            // case i in (m, n], reverse it
            if (i > m) {
                ListNode* nextOne = now->next;
                now->next = last;
                last = now;
                now = nextOne;
                continue;
            }

            now = now->next;
        }

        if (left_pre == NULL)
            head = left_pre = right;
        else
            left_pre->next = right;

        left->next = right_next;

        return head;
    }
};


int main() {
    Solution s;

    ListNode* head = new ListNode(1);
    for (int i = 2; i <= 10; ++i)
        head->append(i);

    printf("between 2 and 9:\n");
    head = s.reverseBetween(head, 2, 9);
    head->print();
    head = s.reverseBetween(head, 2, 9);
    head->print();

    printf("\ninclude the head:\n");
    head = s.reverseBetween(head, 1, 9);
    head->print();
    head = s.reverseBetween(head, 1, 9);
    head->print();

    printf("\nreverse the total list:\n");
    head = s.reverseBetween(head, 1, 10);
    head->print();
    head = s.reverseBetween(head, 1, 10);
    head->print();


    printf("\nreverse one element:\n");
    head = s.reverseBetween(head, 1, 1);
    head->print();
    head = s.reverseBetween(head, 1, 1);
    head->print();

    return 0;
}

C. 二进制的反转

原题:https://leetcode.com/problems/reverse-bits/
给定一个无符号整数,要求将其二进制形式翻转一下,比如010111将变成111010,主要是位操作,掩码的基础知识,倒没什么特殊的技巧。

#include <stdio.h>
#include <assert.h>


typedef unsigned int uint32_t;

class Solution {
public:
    uint32_t reverseBits(uint32_t n) {
        uint32_t ans = 0, mask = 1u;
        for (int i = 0; i < 32; ++i) {
            ans = ans << 1;
            if ((n & mask) != 0)
                ans |= 1u;
            mask = mask << 1;
        }

        return ans;
    }
};


int main() {
    Solution s;

    assert(s.reverseBits(0u) == 0u);
    assert(s.reverseBits(1u) == 2147483648u);
    assert(s.reverseBits(43261596u) == 964176192u);

    return 0;
}

D. 反转int数字

原题:https://leetcode.com/problems/reverse-integer/
这道题主要是要考虑如何判断是否会溢出,查阅网上资料后,觉得“未雨绸缪”法比较可取:

#include <stdio.h>
#include <assert.h>
using namespace std;


class Solution {
public:
    int reverse(int x) {
        int My_INT_MAX = (1u << 31) - 1, My_INT_MIN = -(1u << 31);
        bool neg = false;
        if (x == 0)
            return 0;
        if (x < 0) {
            if (x == My_INT_MIN)
                return 0;
            neg = true;
            x = -x;
        }

        int ans = 0;
        while (x > 0) {
            if (ans > My_INT_MAX / 10)
                return 0;
            ans *= 10;
            int key = x % 10;
            if (ans > My_INT_MAX - key)
                return 0;
            ans += key;
            x /= 10;
        }

        if (neg)
            return -ans;
        return ans;
    }
};


int main() {
    Solution s;

    assert(s.reverse(0) == 0);
    assert(s.reverse(-1) == -1);
    assert(s.reverse(-123) == -321);
    assert(s.reverse(234) == 432);
    assert(s.reverse(1234567809) == 0);
    assert(s.reverse(-2147483648) == 0);
    assert(s.reverse(2147483647) == 0);

    return 0;
}

E. 反转句子中的单词

原题:https://leetcode.com/problems/reverse-words-in-a-string/
即把the sky is blue变成blue is sky the
这个问题本身不难,难的是,能否做到O(1)的空间开销?
答案是可以的哈哈,第一次自己解决这样“精巧”的题目,之前稍微思维有点绕的题目都得看题解才能知道,否则就是各种暴力咕~~(╯﹏╰)b。
我的思路是:先将整个字符串按字符反转,比如the sky is blue变成eulb si yks eht,这样子有什么用呢?其实跟华容道这个游戏有点相似,你先把要“运输”的东西运送到目的地,然后再“转个身”,就好啦,具体的转身在这里就是——对每个单词(按照空格将其分开),内部再反转一次,就会变成:blue is sky the,具体实现代码如下:

#include <stdio.h>
#include <vector>
#include <string>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <assert.h>
#include <algorithm>
#include <ctime>
#include <cstdlib>
#include <cmath>
using namespace std;


class Solution {
public:
    // need in-place and O(1) space to solve
    void reverseWords(string& s) {
        // first, you should get enough space to reverse each word
        // but notice that each word is exactly equal to itself in size!!!!!!
        // this is the most important property to solve this problem in O(1) space
        if (s.empty() || s == " ") {
            s = "";
            return;
        }

        int start = -1, len = s.size();
        reverseHelper(s, 0, len-1);

        for (int i = 0; i < len; ++i) {
            if (start == -1 && s[i] != ' ')
                start = i;
            else if (start != -1 && (s[i] == ' ' || i == len-1)) {
                int tail = i - 1;
                if (i == len-1 && s[i] != ' ')
                    tail = i;
                reverseHelper(s, start, tail);
                // printf("i=%d, s=%s, start=%d, tail=%d\n", i, s.data(), start, tail);
                start = -1;
            }
        }
    }

    void reverseHelper(string& s, int beg, int end) {
        for (int i = beg, j = end; i < j; ++i, --j)
            swap(s[i], s[j]);
    }
};


int main() {
    Solution s;

    string str("hello jacket");
    printf("Original str=%s\n", str.data());
    s.reverseWords(str);
    printf("After reversing, str=%s\n", str.data());

    return 0;
}

F. 在双向链表中删除一个值(并返回删除的个数)

这个是题外话了,无关reverse的主题,不过也是个有趣的问题,细节需要处理好——比如删除的值如果是在链表的头部,那该怎么办?代码感觉还是有点复杂了,可以再简化一下:

#include <stdio.h>

struct DList
{
    int val;
    DList *prev, *next;
    DList(int v): val(v), prev(NULL), next(NULL) {}
};

DList* delHelper(DList* pos) {
    DList* next = pos->next;
    DList* prev = pos->prev;
    if (prev != NULL)
        prev->next = next;
    if (next != NULL)
        next->prev = prev;
    // delete pos;  // if necessary

    return next;
}

int delVal(DList*& head, int val) {
    int cnt = 0;

    DList* now = head;
    bool first = true;
    while (now != NULL) {
        if (now->val == val) {
            now = delHelper(now);
            ++cnt;
        }
        else {
            if (first) {
                first = false;
                head = now;
            }
            now = now->next;
        }
    }

    // 如果全部都被删掉了,那么head自然就是NULL了
    if (first)
        head = NULL;

    return cnt;
}

void joint(DList* a, DList* b) {
    a->next = b;
    b->prev = a;
}

void print(DList* head) {
    DList* now = head;
    bool first = true;
    while (now != NULL) {
        if (first) {
            first = false;
            printf("%d", now->val);
        }
        else
            printf(" -> %d", now->val);
        now = now->next;
    }
    printf("\n");
}

int main() {
    DList* list[10];
    for (int i = 0; i < 10; ++i)
        list[i] = new DList(i/2);

    for (int i = 0; i < 9; ++i)
        joint(list[i], list[i+1]);

    DList* head = list[0];
    print(head);

    delVal(head, 0);
    print(head);

    delVal(head, 3);
    delVal(head, 4);
    print(head);

    return 0;
}

你可能感兴趣的:(LeetCode,链表)