剑指力扣

剑指力扣

链表

206 反转链表 & 剑指 Offer 24 反转链表(简单)

206 反转链表 & 剑指 Offer 24 反转链表

执行用时:8 ms, 在所有 C++ 提交中击败了90.86%的用户

内存消耗:8.5 MB, 在所有 C++ 提交中击败了58.16%的用户

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        if (head == nullptr || head->next == nullptr) return head;
        if (head->next->next == nullptr) {
            ListNode* phead = head->next;
            head->next->next = head;
            head->next = nullptr;
            return phead;
        }
        ListNode* first = head, * second = first->next, * third = second->next;
        first->next = nullptr;
        while (third != nullptr) {
            second->next = first;
            first = second;
            second = third;
            third = third->next;
        }
        second->next = first;
        return second;
    }
};

注释:经常看看,记住关键步骤即可

876 链表的中间结点(简单)

876 链表的中间结点

法一:两次遍历

执行用时:4 ms, 在所有 C++ 提交中击败了35.09%的用户

内存消耗:7 MB, 在所有 C++ 提交中击败了10.13%的用户

class Solution {
public:
    ListNode* middleNode(ListNode* head) {
        if (head == nullptr) return nullptr;
        ListNode* p = head;
        int count = 1;
        while (p->next != 0) {
            p = p->next;
            count++;    
        }
        count /= 2;
        p = head;
        for (int i = 0; i < count; i++) {
            p = p->next;
        }
        return p;
    }
};

法二:快慢指针

执行用时:4 ms, 在所有 C++ 提交中击败了35.09%的用户

内存消耗:6.9 MB, 在所有 C++ 提交中击败了32.93%的用户

class Solution {
public:
    ListNode* middleNode(ListNode* head) {
        if (head == nullptr) return nullptr;
        ListNode* p = head;
        int count = 1;
        while (p->next != 0) {
            p = p->next;
            count++;    
        }
        count /= 2;
        p = head;
        for (int i = 0; i < count; i++) {
            p = p->next;
        }
        return p;
    }
};

剑指 Offer 06 从尾到头打印链表(简单)

剑指 Offer 06 从尾到头打印链表

执行用时:12 ms, 在所有 C++ 提交中击败了28.33%的用户

内存消耗:9 MB, 在所有 C++ 提交中击败了39.63%的用户

class Solution {
public:
    vector<int> reversePrint(ListNode* head) {
        if (head == nullptr) return {};
        ListNode* phead = head;
        stack<int> s;
        vector<int> res;
        while (phead != nullptr) {
            s.push(phead->val);
            phead = phead->next;
        }
        while (!s.empty()) {
            res.push_back(s.top());
            s.pop();
        }
        return res;
    }
};

但凡提到反转,都可以考虑一下辅助栈。

1290 二进制链表转整数(简单)

1290 二进制链表转整数

执行用时:0 ms, 在所有 C++ 提交中击败了100.00%的用户

内存消耗:8.5 MB, 在所有 C++ 提交中击败了24.03%的用户

class Solution {
public:
    int getDecimalValue(ListNode* head) {
        int num = 0;
        while (head != nullptr) {
            num = num * 2 + head->val;
            head = head->next;
        }
        return num;
    }
};

141 环形链表(简单)

141 环形链表

执行用时:8 ms, 在所有 C++ 提交中击败了93.73%的用户

内存消耗:7.9 MB, 在所有 C++ 提交中击败了29.02%的用户

快慢指针法:

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

24. 两两交换链表中的节点(简单)

24. 两两交换链表中的节点

执行用时:4 ms, 在所有 C++ 提交中击败了72.30%的用户

内存消耗:7.9 MB, 在所有 C++ 提交中击败了7.02%的用户

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        if (head == nullptr || head->next == nullptr) return head;
        ListNode* phead = new ListNode, * first = phead, * second = head, * third = head->next;
        phead->next = head;
        while (third != nullptr) {
            first->next = third;
            second->next = third->next;
            third->next = second;
            if (second->next == nullptr || second->next->next == nullptr) break;
            first = second;
            second = second->next;
            third = second->next;
        }
        return phead->next;
    }
};

找准“中间态”即可。

2. 两数相加

2. 两数相加

执行用时:56 ms, 在所有 C++ 提交中击败了43.45%的用户

内存消耗:69.4 MB, 在所有 C++ 提交中击败了88.33%的用户

class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        ListNode* p1 = l1, * p2 = l2;
        int len1 = 0, len2 = 0;
        while (p1 != nullptr) { p1 = p1->next; len1++; }
        while (p2 != nullptr) { p2 = p2->next; len2++; }
        if (len1 < len2) return addTwoNumbers(l2, l1);
        p1 = l1, p2 = l2;
        while (p2 != nullptr) {
            p1->val += p2->val;
            p1 = p1->next, p2 = p2->next;
        }
        p1 = l1;
        while (p1->next != nullptr) {
            if (p1->val > 9) {p1->val -= 10; p1->next->val++; }
            p1 = p1->next;
        }
        if (p1->val > 9) {
            ListNode* new_node = new ListNode;
            new_node->next = nullptr;
            new_node->val = 1;
            p1->next = new_node;
            p1->val -= 10;
        }
        return l1;
    }
};

数组

剑指 Offer 03. 数组中重复的数字(简单)

剑指 Offer 03. 数组中重复的数字

法一:哈希表

执行用时:132 ms, 在所有 C++ 提交中击败了30.13%的用户

内存消耗:27.3 MB, 在所有 C++ 提交中击败了20.05%的用户

class Solution {
public:
    int findRepeatNumber(vector<int>& nums) {
        unordered_set<int> table;
        for (int i = 0; i < nums.size(); i++) {
             if (table.count(nums[i]) > 0) return nums[i];
            table.insert(nums[i]);
            //思考:为什么下面不行?
            // table.insert(nums[i]);
            // if (table.count(nums[i]) > 1) return nums[i]; 
        }
        return 0;
    }
};

法二:原地置换

无~

剑指 Offer 45. 把数组排成最小的数(中等)

剑指 Offer 45. 把数组排成最小的数

执行用时:12 ms, 在所有 C++ 提交中击败了72.75%的用户

内存消耗:11.7 MB, 在所有 C++ 提交中击败了14.89%的用户

class Solution {
public:
    static bool str_cmp(const string& str1, const string& str2) {
        return str1 + str2 < str2 + str1 ? true : false;
    }
    string minNumber(vector<int>& nums) {
        int n = nums.size();
        vector<string> str;
        string res = "";
        if (n == 0) return res;
        for (int i = 0; i < n; i++) str.push_back(to_string(nums[i]));
        sort(str.begin(), str.end(), str_cmp);
        for (int j = 0; j < str.size(); j++) res += str[j];
        return res;
    }
};

难点:

1.定义排序规则:若字符串 x + y > y + x。则定义 x > y。

2.定义排序函数

剑指 Offer 56 - II. 数组中数字出现的次数 II(中等)

剑指 Offer 56 - II. 数组中数字出现的次数 II

法一:哈希表

执行用时:76 ms, 在所有 C++ 提交中击败了74.05%的用户

内存消耗:18.4 MB, 在所有 C++ 提交中击败了24.49%的用户

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        unordered_map<int, int> table;
        for (int i = 0; i < nums.size(); i++) table[nums[i]]++;
        for (unordered_map<int, int>::iterator it = table.begin(); it != table.end(); it++) 
            if (it->second == 1) 
                return it->first;
        /*用下标访问也可:
        for (int i = 0; i < nums.size(); i++) 
            if (table[nums[i]] == 1) 
                return nums[i];
        */
        return -1;
    }
};

法二:二进制各位数字出现的次数

执行用时:80 ms, 在所有 C++ 提交中击败了68.87%的用户

内存消耗:16.4 MB, 在所有 C++ 提交中击败了33.36%的用户

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int res = 0, arr[32] = { 0 };  //记录各个位上1的个数
        for (int i = 0; i < nums.size(); i++) {
            for (int j = 0; j < 32; j++) {
                if (nums[i] % 2 != 0) arr[j]++;
                nums[i] /= 2;
            }
        }
        for (int k = 0; k < 32; k++) 
            if (arr[k] % 3 != 0) 
                res += pow(2, k);
        return res;
    }
};

46. 全排列

46. 全排列

执行用时:4 ms, 在所有 C++ 提交中击败了92.27%的用户

内存消耗:7.8 MB, 在所有 C++ 提交中击败了86.53%的用户

class Solution {
public:
    int Num(int num) {
        int res = 1;
        for (int i = 1; i <= num; i++) res *= i;
        return res;
    }

    vector<vector<int>> permute(vector<int>& nums) {
        vector<vector<int> > res;
        for (int i = 0; i < Num(nums.size()); i++) {
            res.push_back(nums);
            next_permutation(nums.begin(), nums.end());
        }
        return res;
    }
};

使用algorithm中的next_permutation函数会使这道题变得很无脑。以后有机会尝试用其他方法解决。

不要过度依赖algorithm库!

239. 滑动窗口最大值(困难)

239. 滑动窗口最大值

滑动窗口法:(超时)

class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        vector<int> res;
        for (int i = 0; i < nums.size() - k + 1; i++) {
            int max = INT_MIN;
            for (int j = 0; j < k; i++) {
                if (nums[j] > max) max = nums[j];
            }
            res.push_back(max);
        }
        return res;
    }
};

字符串

387. 字符串中的第一个唯一字符(简单)

387. 字符串中的第一个唯一字符

执行用时:28 ms, 在所有 C++ 提交中击败了80.91%的用户

内存消耗:10.6 MB, 在所有 C++ 提交中击败了93.55%的用户

class Solution {
public:
    int firstUniqChar(string s) {
        int table[26] = { 0 };
        for (int i = 0; i < s.size(); i++) 
            table[s[i] - 'a']++;
        for (int j = 0; j < s.size(); j++) 
            if (table[s[j] - 'a'] == 1) 
                return j;
        return -1;
    }
};

567. 字符串的排列(中等)

567. 字符串的排列

执行用时:368 ms, 在所有 C++ 提交中击败了5.02%的用户

内存消耗:7.4 MB, 在所有 C++ 提交中击败了79.27%的用户

滑动窗口+哈希表

class Solution {
public:
    bool checkInclusion(string s1, string s2) {
        int n1 = s1.size(), n2 = s2.size(), table[26] = { 0 };
        for (int i = 0; i < n1; i++) table[s1[i] - 'a']++;
        for (int j = 0; j < n2; j++) {
            int tmp[26];  //创建table的复制版
            for (int k = 0; k < 26; k++) tmp[k] = table[k];
            int count = 0, index_s2 = j;
            while (index_s2 < n2 && tmp[s2[index_s2++] - 'a']-- > 0) count++;
            if (count == n1) return true;
        }
        return false;
    }
};

14.最长公共前缀(简单)

14. 最长公共前缀

执行用时:4 ms, 在所有 C++ 提交中击败了92.77%的用户

内存消耗:9.5 MB, 在所有 C++ 提交中击败了33.07%的用户

纵向扫描法

class Solution {
public:
    string longestCommonPrefix(vector<string>& strs) {
        if (strs.size() == 0) return "";
        string res = "";
        for (int j = 0; ; j++) {  //i代表行数,j代表列数
            for (int i = 0; i < strs.size(); i++) {
               char c = strs[0][j];
               if (c != strs[i][j] || j == strs[i].size()) return res;
            }
            res += strs[0][j];
        }
        return res;
    }
};

可以尝试横向扫描法。

贪心

455. 分发饼干(简单)

455. 分发饼干

执行用时:32 ms, 在所有 C++ 提交中击败了99.05%的用户

内存消耗:17.1 MB, 在所有 C++ 提交中击败了98.40%的用户

class Solution {
public:
    int findContentChildren(vector<int>& g, vector<int>& s) {
        sort(g.begin(), g.end());
        sort(s.begin(), s.end());
        int index_s = 0, index_g = 0;
        while (index_s < s.size() && index_g < g.size())
            if (g[index_g] <= s[index_s]) { index_s++; index_g++; }
            else index_s++;
        return index_g;
    }
};

贪心的标志算法

55.跳跃游戏(中等)

55. 跳跃游戏

执行用时:8 ms, 在所有 C++ 提交中击败了99.24%的用户

内存消耗:12.5 MB, 在所有 C++ 提交中击败了94.64%的用户

class Solution {
public:
    bool canJump(vector<int>& nums) {
        int dist = 0;
        for (int i = 0; i <= dist && i < nums.size(); i++)
            dist = max(dist, nums[i] + i);
        return dist >= nums.size() - 1;
    }
};

45. 跳跃游戏II

45. 跳跃游戏 II

执行用时:8 ms, 在所有 C++ 提交中击败了99.81%的用户

内存消耗:15.1 MB, 在所有 C++ 提交中击败了93.23%的用户

class Solution {
public:
    int jump(vector<int>& nums) {
        if (nums.size() == 1) return 0;
        int left = 0, right = 0, steps = 0;  //用left和right维护一个区间
        while (left <= right) {
            int max_r = 0;
            for (int i = left; i <= right; i++)
                max_r = max(max_r, nums[i] + i);
            left = right, right = max_r;
            steps++;
            if (right >= (int)nums.size() - 1) break;
        }
        return steps;
    }
};

位运算

231. 2的幂(简单)

231. 2的幂

方法一:

执行用时:0 ms, 在所有 C++ 提交中击败了100.00%的用户

内存消耗:5.7 MB, 在所有 C++ 提交中击败了98.60%的用户

class Solution {
public:
    bool isPowerOfTwo(int n) {
        return n > 0 && (1 << 30) % n == 0;
    }
};

方法二:

执行用时:0 ms, 在所有 C++ 提交中击败了100.00%的用户

内存消耗:5.8 MB, 在所有 C++ 提交中击败了97.10%的用户

class Solution {
public:
    bool isPowerOfTwo(int n) {
        return n > 0 && (n & -n) == n;
    }
};

x & -x表示x的二进制中最靠近右边的1及以后的数

762. 二进制表示中质数个计算置位(简单)

762. 二进制表示中质数个计算置位

执行用时:40 ms, 在所有 C++ 提交中击败了39.26%的用户

内存消耗:6.2 MB, 在所有 C++ 提交中击败了58.97%的用户

class Solution {
public:
    int countPrimeSetBits(int L, int R) {
        unordered_set<int> table = { 2,3,5,7,11,13,17,19,23,29,31 };
        int num = 0;
        for (int i = L; i <= R; i++) {
            int n = 0;
            for (int j = i; j; j >>= 1) n += (j & 1);  //计算二进制1的个数。常见技巧!
            if (table.count(n)) num++;
        }
        return num; 
    }
};

136. 只出现一次的数字

136. 只出现一次的数字

执行用时:12 ms, 在所有 C++ 提交中击败了99.83%的用户

内存消耗:16.5 MB, 在所有 C++ 提交中击败了96.73%的用户

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int ret = 0;
        for (auto x : nums) ret ^= x;
        return ret;
    }
};

t countPrimeSetBits(int L, int R) {
unordered_set table = { 2,3,5,7,11,13,17,19,23,29,31 };
int num = 0;
for (int i = L; i <= R; i++) {
int n = 0;
for (int j = i; j; j >>= 1) n += (j & 1); //计算二进制1的个数。常见技巧!
if (table.count(n)) num++;
}
return num;
}
};




### 136. 只出现一次的数字

[136. 只出现一次的数字](https://leetcode-cn.com/problems/single-number/)

>执行用时:12 ms, 在所有 C++ 提交中击败了99.83%的用户
>
>内存消耗:16.5 MB, 在所有 C++ 提交中击败了96.73%的用户

~~~cpp
class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int ret = 0;
        for (auto x : nums) ret ^= x;
        return ret;
    }
};

技巧: a ^ a = 0 a ^ 0 = a

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值