力扣-数组/字符串/链表

 方法总结

1.哈希映射
    数组:确定数量
    集合:去重
    字典:需要同时处理value和下标
2.双指针
    left/right向中间夹逼
    low/fast快慢指针向一个方向移动
    时间尺度上,right指向的是目标(结果)数组,letf指向的是当前(待处理)数组,参考移除元素
3.滑动窗口
    left/right指针,当窗口内满足条件时操作左右指针
3.二分查找
    有序数组,有时间限制
4.求和或者求差
    反向思维:求和就是球差、求差就是求和
5.字符串翻转
    部分翻转和整体翻转配合
6.单调栈
    处理求元素左右第一个最大/最小问题
    

 707. 设计链表

class MyLinkedList {
private:
    struct LinkedListNode{
        int val;
        struct LinkedListNode* next;    //这里包括以下不需要struct,跟C语言的区别
        LinkedListNode(int val):val(val), next(nullptr){};//默认构造函数,
    };

    int len;
    struct LinkedListNode* head;
public:
    MyLinkedList() {
        head = new struct LinkedListNode(0);//没有参数出错,已经没有无参数的构造函数
        len = 0;
    }
    
    int get(int index) {//index从0开始,区别于len
        if (index > (len - 1) || index < 0) {
            return -1;
        }
        struct LinkedListNode* cur = head->next;
        while(index--){
            cur = cur->next;
        }
        print();
        return cur->val;
    }
    
    void addAtHead(int val) {
        struct LinkedListNode* node = new struct LinkedListNode(val);
        node->next = head->next;
        head->next = node;
        len++;
        print();
    }
    
    void addAtTail(int val) {
        struct LinkedListNode* cur = head;
        while(cur->next != nullptr){
            cur = cur->next;
        }
        struct LinkedListNode* node = new struct LinkedListNode(val);
        cur->next = node;
        len++;
        print();
    }
    
    void addAtIndex(int index, int val) {
        if(index > len) return;
        if(index < 0) index = 0;  
        LinkedListNode* newNode = new LinkedListNode(val);
        LinkedListNode* cur = head;
        while(index--) {
            cur = cur->next;
        }
        newNode->next = cur->next;
        cur->next = newNode;
        len++;
        print();
    }
    
    void deleteAtIndex(int index) {
        if(index > len-1 || index < 0)
        {
            return;
        }
        struct LinkedListNode* cur = head;
        while(index--){
            cur = cur->next;
        }
        struct LinkedListNode* tem = cur->next;
        cur->next = cur->next->next;
        delete tem;
        len--;
        print();
    }
    void print(){
        LinkedListNode* cur = head->next;
        while(cur != nullptr){
            std::cout << cur->val << "  ";
            cur = cur->next;
        }
        std::cout << std::endl;
    }
};

/**
 * Your MyLinkedList object will be instantiated and called as such:
 * MyLinkedList* obj = new MyLinkedList();
 * int param_1 = obj->get(index);
 * obj->addAtHead(val);
 * obj->addAtTail(val);
 * obj->addAtIndex(index,val);
 * obj->deleteAtIndex(index);
 */

206. 反转链表

        摘取旧链表节点,再用头插法创建 

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        if(head == nullptr) return head;
        ListNode* newhead = new ListNode(0);
        ListNode* cur = head;
        while(cur != nullptr)//cur->next会漏掉最后一个
        {
            ListNode* tem = cur->next;
            cur->next= newhead->next;
            newhead->next = cur;
            cur = tem;
        }
        return newhead->next;

    }
};

 19. 删除链表的倒数第 N 个结点

        双指针,fast比slow快N+1步,当fast指向最后一个节点的时候,slow指向待删除节点前一个。 

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* newhead = new ListNode();//需要增加头节点,否则对于head:[2]->null无法处理
        newhead->next = head;
        ListNode* slow = newhead;
        ListNode* fast = newhead;
        while(n--){
            fast = fast->next;
        }
        
        while(fast->next != nullptr){
            slow = slow->next;
            fast = fast->next;
        }
        ListNode* tem = slow->next;
        slow->next = slow->next->next;
        delete tem;
        tem = nullptr;
        return newhead->next;
    }
};

链表相交

        计算两条链表长度差,长的那条提前走长度差的步数(尾对齐),同时往前走找交点。

/**
 * 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) {
        //计算长度差
        ListNode* cur = headA;
        int sizeA = 0;
        int sizeB = 0;

        while(cur != nullptr){
            sizeA++;
            cur = cur->next;
        }
        cur = headB;
        while(cur!= nullptr){
            sizeB++;
            cur = cur->next;
        }
        // std::cout<<sizeA<< ' '<<sizeB;

        //长的链表多走差值的步数
        ListNode* curA = headA;
        ListNode* curB = headB;
        for(int i = abs(sizeA - sizeB); i > 0; i--){
            if(sizeA > sizeB){
                curA = curA->next;
            }
            else{
                curB = curB->next;
            }
        }
        // std::cout<< curA->val <<' '<<curB->val;
        
        //同时走,当遇到节点地址相同时,表示该节点是交点
        while(curA != nullptr){
            if(curA == curB){
                return curA;
            }
            curA = curA->next;
            curB = curB->next;
        }
        return nullptr;
    }
};

242. 有效的字母异位词

class Solution {
public:
    bool isAnagram(string s, string t) {
        vector<int> n(26, 0);
        for(int i = 0; i < s.size(); i++)
        {
            n[s[i]-'a']++;
        }
        for(int i = 0; i < t.size(); i++)
        {
            n[t[i]-'a']--;
            if(n[t[i]-'a'] < 0) return false;
        }
        for(int i = 0; i < n.size(); i++)
        {
            if(n[i] != 0) return false;
        }
        return true;
    }
};

349. 两个数组的交集

class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        unordered_set<int> result;
        unordered_set<int> set;
        for(int n : nums1){
            set.insert(n);
        }
        //改进 unordered_set<int> set(nums1.begin(), nums1.end());

        for(int n : nums2){
            if(set.find(n) != set.end()){
                result.insert(n);
            }
        }
        return vector<int>(result.begin(), result.end());
    }
};

 202. 快乐数

class Solution {
public:
    
    bool isHappy(int n) {
        unordered_set<int> set;
        while(1){
            //sum置零
            int sum = 0;
            //计算各位置的平方和
            while(n != 0){
            int tem = n % 10;
            n = n / 10;
            sum += tem*tem;
            }
            std::cout << sum << std::endl;
            //是快乐数
            if(sum == 1) return true;
            //重复返回false
            if(set.find(sum) != set.end()){
                return false;
            }
            //不重复添加进set
            set.insert(sum);
            //继续计算
            n = sum;
        }
        return true;
    }
};

1. 两数之和

找出map中是否有target-nums[i],

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map<int, int> hash;
        for(int i = 0 ;i < nums.size(); i++)
        {
            if(hash.find(target - nums[i]) != hash.end())
            {
                return {i, hash[target - nums[i]]};
            }
            else{
                hash[nums[i]] = i;
            }
        }
        return {};
    }
};

454. 四数相加 II

          先计算nums1+nums2再计算nums3+nums4,最后找和==0,会超时。 

class Solution {
public:
    int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
        int res = 0;
        map<int, int> hash;
        for(int i : nums1){
            for(int j : nums2){
                hash[i+j]++;
            }
        }
        for(int i:nums3){
            for(int j:nums4){
                if(hash.find(0-(i+j)) != hash.end()){
                    res+= hash[0-(i+j)];
                }
            }
        }
        return res;
    }
};

 383. 赎金信

class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {
        vector<int> hash(26, 0);
        for(int i = 0; i < magazine.size(); i++){
            hash[magazine[i]-'a']++;
        }
        for(int i = 0; i < ransomNote.size(); i++){
            hash[ransomNote[i]-'a']--;
            if(hash[ransomNote[i]-'a'] < 0){
                return false;
            }
        }
        return true;
    }
};

26. 删除有序数组中的重复项

使用双指针 

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        int left = 0;
        int right = 1;
        while(right < nums.size())
        {
            if(nums[left] == nums[right])
            {
                right++;//数字相同时,right右移
            }
            else
            {
                nums[++left] = nums[right++];//不同时
            }
        }
        return left + 1;
    }
};

27. 移除元素

双指针

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int lowIndex =0;
        for(int fastIndex = 0; fastIndex < nums.size();fastIndex++)
        {
            if(nums[fastIndex]!=val)
            {
                nums[lowIndex++] = nums[fastIndex];
            }
        }
        return lowIndex;
    }
};

66. 加一

我写的,能过一半用例,笨方法。只是想确定一下笨方法可不可行,不管笨不笨,能拿到分就是好方法。
class Solution {
public:
    vector<int> plusOne(vector<int>& digits) {
        stack<int> stack;
        vector<int> res;
        uint num = 0;
        uint cont = 1;
        for(int i = digits.size()-1;i >= 0;i--)
        {
            num += digits[i]*cont;
            cont *= 10;
        }
        cout <<num;
        num += 1;
    
        while(num!=0)
        {
            stack.push(num%10);
            num = num/10;
        }
        while(!stack.empty())
        {
            res.push_back(stack.top());
            stack.pop();
        }
        return res;
    }
};

比较好的方法,使用笨方法的原因也是不知道vector可以很方便的在头插入数据。
class Solution {
public:
    vector<int> plusOne(vector<int>& digits) {
        int len = digits.size();
        for(int i = len - 1; i >=0; i--)
        {
            if(++digits[i] < 10)
            {
                return digits;
            }
            else
            {
                digits[i] = digits[i] % 10;
            }
        }
        digits.insert(digits.begin(), 1);
        return digits;
    }
};

88. 合并两个有序数组

题目没限制就用sort

class Solution {
public:
    void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
        for(int i = 0; i !=n;i++)
        {
            nums1[m+i] = nums2[i];
        }
        sort(nums1.begin(), nums1.end());
    }
};

 由于是数组,不好在nums1上进行操作,既然题目没限制,就用额外空间去存,然后转到nums1上。

我写的
class Solution {
public:
    void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
        int i = 0,j=0;
        vector<int> res;
        while(i!=m&&j!=n)
        {
            if(nums1[i] <= nums2[j])
            {
                res.push_back(nums1[i]);
                i++;
            }
            else
            {
                res.push_back(nums2[j]);
                j++;
            }
        }
        if(i == m)
        {
            while(j!=n)
            {
                res.push_back(nums2[j++]);
            }
        }
        else{
            while(i!=m)
            {
                res.push_back(nums1[i++]);
            }
        }
        for (int i = 0; i != m + n; ++i) {
            nums1[i] = res[i];
        }
    }
};


力扣写的
class Solution {
public:
    void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
        int p1 = 0, p2 = 0;
        int sorted[m + n];
        int cur;
        while (p1 < m || p2 < n) {
            if (p1 == m) {
                cur = nums2[p2++];
            } else if (p2 == n) {
                cur = nums1[p1++];
            } else if (nums1[p1] < nums2[p2]) {
                cur = nums1[p1++];
            } else {
                cur = nums2[p2++];
            }
            sorted[p1 + p2 - 1] = cur;
        }
        for (int i = 0; i != m + n; ++i) {
            nums1[i] = sorted[i];
        }
    }
};

作者:力扣官方题解
链接:https://leetcode.cn/problems/merge-sorted-array/solutions/666608/he-bing-liang-ge-you-xu-shu-zu-by-leetco-rrb0/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

1365. 有多少小于当前数字的数字

 排序后从后往前,元素所在位置的下标就是第几大

class Solution:
    def smallerNumbersThanCurrent(self, nums: List[int]) -> List[int]:
        hash = [0]*101
        tem = nums[:]
        tem.sort()
        for index in range(len(tem)-1,-1,-1): #注意从后往前
            hash[tem[index]] = index
        # res = [0]*len(nums)
        for i in range(len(nums)-1,-1,-1):
            nums[i] = hash[nums[i]]
        return nums

941. 有效的山脉数组

class Solution:
    def validMountainArray(self, arr: List[int]) -> bool:
        left = 0
        right = len(arr) -1
        while left<len(arr)-1 and arr[left+1]>arr[left]:
            left += 1
        while right>0 and arr[right-1] > arr[right]:
            right -= 1
        if left == right and left != 0 and right != len(arr)-1:
            return True
        else:
            return False

1207. 独一无二的出现次数

class Solution:
    def uniqueOccurrences(self, arr: List[int]) -> bool:
        hash = dict()
        for i in range(len(arr)):
            hash[arr[i]] = hash.get(arr[i], 0) + 1
        value = sorted(hash.values())
        for i in range(len(value)-1):
            if(value[i] == value[i+1]):
                return False
        return True

 189. 轮转数组

翻转字符串相似,先整体翻转,再两个部分翻转

注意:k可能大于串长,需要取余操作

class Solution {
public:
    void rotate(vector<int>& nums, int k) {
        k = k % nums.size();
        reverse(nums.begin(), nums.end()); #必须先翻转整个
        reverse(nums.begin(), nums.begin() + k);
        reverse(nums.begin() + k, nums.end());

    }
};

python不支持list部分翻转,没写翻转法 

class Solution:
    def rotate(self, nums: List[int], k: int) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        k = k%len(nums)
        nums[:] = nums[-k:] + nums[0:-k]    #这里必须是nums[:]对原列表进行修改

 724. 寻找数组的中心下标

class Solution:
    def pivotIndex(self, nums: List[int]) -> int:
        s = sum(nums)
        leftsum = 0
        rightsum = 0
        for i in range(len(nums)):
            leftsum += nums[i]  #多一个nums[i]
            rightsum = s - leftsum + nums[i]    #多加一个nums[i]与左边保持相等
            if leftsum == rightsum:
                return i
        return -1

922. 按奇偶排序数组 II

 哈希+双指针,一趟遍历可以结束

class Solution:
    def sortArrayByParityII(self, nums: List[int]) -> List[int]:
        res = [0]*len(nums)
        odd = 1
        even = 0
        index = 0
        while odd <len(nums) or even < len(nums):
            tem = nums[index]%2
            if tem == 0:
                res[even] = nums[index]
                even += 2
                index += 1
            elif tem == 1:
                res[odd] = nums[index]
                odd += 2
                index += 1
        return res

35. 搜索插入位置

插入位置为left 

class Solution:
    def searchInsert(self, nums: List[int], target: int) -> int:
        length = len(nums)
        left = 0
        right = length - 1
        while left <= right:
            mid = int(left + (right - left)/2)
            if target > nums[mid]:
                left = mid + 1
            elif target < nums[mid]:
                right = mid - 1
            else:
                return mid
        return left

 744. 寻找比目标字母大的最小字母

class Solution {
public:
    char nextGreatestLetter(vector<char>& letters, char target) {
        if(target >= letters[letters.size() - 1])
            return letters[0];
        int low = 0;
        int mid;
        int high = letters.size()-1;
        while(low <= high)
        {
            mid = (low+high)/2;
            if(target > letters[mid])
            {
                low = mid + 1;
            }
            else if(target < letters[mid])
            {
                high = mid -1;
            }else{
                std::cout<< mid;
                while(letters[mid] == letters[mid + 1]) mid++;//多个相同时可能会定位在中间
                return letters[mid + 1];
            }
        }
        return letters[high + 1];
    }
};

单调栈

 739. 每日温度

class Solution:
    def dailyTemperatures(self, temperatures: List[int]) -> List[int]:
        stack = [0]
        res = [0] * len(temperatures)
        for i in range(1, len(temperatures)):
            while len(stack)>0 and temperatures[i] > temperatures[stack[-1]]:
                res[stack[-1]] = i  - stack[-1]
                stack.pop()
            stack.append(i)
        return res

496. 下一个更大元素 I

class Solution:
    def nextGreaterElement(self, nums1: List[int], nums2: List[int]) -> List[int]:
        res = [-1]*len(nums1)
        # print(nums2.index(1))
        for index, num in enumerate(nums1):
            for i in nums2[nums2.index(num)+1:]:
                if i > num:
                    res[index] = i
                    break
        return res

503. 下一个更大元素 II

可以把两个数组拼一块 

class Solution:
    def nextGreaterElements(self, nums: List[int]) -> List[int]:

42. 接雨水

class Solution:
    def trap(self, height: List[int]) -> int:
        # 单调栈
        '''
        单调栈是按照 行 的方向来计算雨水
        从栈顶到栈底的顺序:从小到大
        通过三个元素来接水:栈顶,栈顶的下一个元素,以及即将入栈的元素
        雨水高度是 min(凹槽左边高度, 凹槽右边高度) - 凹槽底部高度
        雨水的宽度是 凹槽右边的下标 - 凹槽左边的下标 - 1(因为只求中间宽度)
        '''
        # stack储存index,用于计算对应的柱子高度
        stack = [0]
        result = 0
        for i in range(1, len(height)):
            # 情况一
            if height[i] < height[stack[-1]]:
                stack.append(i)

            # 情况二
            # 当当前柱子高度和栈顶一致时,左边的一个是不可能存放雨水的,所以保留右侧新柱子
            # 需要使用最右边的柱子来计算宽度
            elif height[i] == height[stack[-1]]:
                stack.pop()
                stack.append(i)

            # 情况三
            else:
                # 抛出所有较低的柱子
                while stack and height[i] > height[stack[-1]]:
                    # 栈顶就是中间的柱子:储水槽,就是凹槽的地步
                    mid_height = height[stack[-1]]
                    stack.pop()
                    if stack:
                        right_height = height[i]
                        left_height = height[stack[-1]]
                        # 两侧的较矮一方的高度 - 凹槽底部高度
                        h = min(right_height, left_height) - mid_height
                        # 凹槽右侧下标 - 凹槽左侧下标 - 1: 只求中间宽度
                        w = i - stack[-1] - 1
                        # 体积:高乘宽
                        result += h * w
                stack.append(i)
        return result

205. 同构字符串

 判断字符是否相互映射,一旦发现当前映射关系与之前的错误就返回False

class Solution:
    def isIsomorphic(self, s: str, t: str) -> bool:
        dict = {}
        for i in range(len(s)):
            if dict.get(s[i]) == None:
                if t[i] not in dict.values():
                    dict[s[i]] = t[i]
                else:
                    return False
            else:
                if dict[s[i]] != t[i]:
                    return False
        
        return True

925. 长按键入

class Solution:
    def isLongPressedName(self, name: str, typed: str) -> bool:
        i = 0
        j = 0
        while j<len(typed):
            if i < len(name) and  name[i] == typed[j]:
                i += 1
                j += 1
            elif j >0 and typed[j] == typed[j-1]:
                j += 1
            else:
                return False
        if i == len(name):
            return True
        else:
            return False

844. 比较含退格的字符串

使用栈 ,没有做精简

class Solution:
    def backspaceCompare(self, s: str, t: str) -> bool:
        stack1 = []
        stack2 = []
        i = 0
        while i<len(s):
            if s[i] != '#':
                stack1.append(s[i])
            elif s[i] == '#':
                if len(stack1)>0:
                    stack1.pop()
                else:
                    i += 1
                    continue
            i+=1
        i = 0
        while i<len(t):
            if t[i] != '#':
                stack2.append(t[i])
            elif t[i] == '#':
                if len(stack2)>0:
                    stack2.pop()
                else:
                    i+=1
                    continue
            i+=1
        if stack1[:] == stack2[:]:
            return True
        return False

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值