Leetcode上的各种“Reverse”

来源:互联网 发布:java项目实战视频下载 编辑:程序博客网 时间:2024/05/22 16:38

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;}
0 0
原创粉丝点击