leetcode1-3题解

Posted chengdongliang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了leetcode1-3题解相关的知识,希望对你有一定的参考价值。

leetcode 1-3题题解,用C++和python实现

第一题

解题思路
暴力解法
嵌入两层循环:第一层:i 从 0 到 n-2 ; 第二层: j 从 i+1 到 n-1;判断nums[i] +nums[j] == target, 如果成立则是正确答案。时间复杂度O(n^2)

**map解法 O(n*logn)**
把数组存在一个map里边,map的key是数组的值,map的value是数组的下标,这样只需要遍历原数组,查看a = target - nums[i]的值在不在map的key中,如果存在,并且map[a]与i不相等,则这两个值就是需要返回的下标。
时间复杂度O(n),空间复杂度O(n)

代码如下:
C++

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        map<int, int> myset;
        vector<int> results;
        for(auto tmp = nums.begin(); tmp<nums.end(); tmp++)
            myset[*tmp] = tmp - nums.begin();
        for(auto tmp = nums.begin(); tmp<nums.end(); tmp++)
        {
            if(myset.find(target - *tmp) != myset.end() && (*myset.find(target - *tmp)).second != (tmp-nums.begin()))
            {
                results.push_back(tmp-nums.begin());
                results.push_back(myset[target - *tmp]);
                break;
            }
        }
        return results;
    }
};

python

class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        map = {}
        for i in range(len(nums)):
            if map.__contains__(target - nums[i]):
                return [map[target - nums[i]], i]
            map[nums[i]] = i

第二题

解题思路
从左到右遍历链表,以此相加,每一个位置生成一个新的节点

时间复杂度:O(max(len(l1), len2(l2))
考虑边界
进位的处理:carry表示进位,当最后一位还有进位时,即使l1和l2均为NULL的情况下,还需要生成一个新的节点

代码如下:
C++

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        ListNode *head = new ListNode(0); //建立观察节点
        ListNode *temp = head;
        
        int carry = 0; //保留进位
        int sum = 0;
        
        while(l1 || l2)
        {
            if(l1 && l2) //两个链表都非空
            {
                sum = l1->val + l2->val + carry;
                l1 = l1->next;
                l2 = l2->next;
            }
            else if(l1)
            {
                sum = l1->val + carry;
                l1 = l1->next;
            }
            else
            {
                sum = l2->val + carry;
                l2 = l2->next;
            }
            //求出和和进位 添加到新的链表
            carry = sum/10;
            sum = sum % 10;
            head->next = new ListNode(sum);
            head = head->next;
            if((l1 == NULL || l2 == NULL) && carry == 0)
            {
                head->next = l1 ? l1 : l2; //将非空链表的剩余节点添加到新联表中
                return temp->next;
            }
        }
        if (carry) //如果最后以为还有进位
        {
            head->next = new ListNode(carry);
        }
        //head->next->next = NULL;
        
        return temp->next;
    }
};

python

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
        p=result=ListNode (-1)
        temp=0
        while l1 and l2:#当l1和l2属于同长度部分
            sum=l1.val+l2.val+temp
            temp=int(sum/10)
            ptemp=ListNode(sum%10)
            p.next=ptemp
            
            p=p.next
            l1=l1.next
            l2=l2.next
            
        temp1=l1 or l2
            
        while temp1:#当l1和l2属于不同长度部分
            sum=temp1.val+temp
            temp=int(sum/10)
            ptemp=ListNode(sum%10)
            p.next=ptemp
            
            p=p.next
            temp1=temp1.next
        if temp:
            p.next=ListNode(temp)
        return result.next

第三题

如果给一个例子"abcabcbb",让你手动找无重复字符的子串,该怎么找?一个字符一个字符的遍历,比如a,b,c,然后又出现了一个a,那么此时就应该去掉第一次出现的a,然后继续往后,又出现了一个b,则应该去掉一次出现的b,以此类推,最终发现最长的长度为3。所以说,我们需要记录之前出现过的字符,记录的方式有很多,最常见的是统计字符出现的个数,但是这道题字符出现的位置很重要,所以我们可以使用HashMap来建立字符和其出现位置之间的映射。进一步考虑,由于字符会重复出现,到底是保存所有出现的位置呢,还是只记录一个位置?我们之前手动推导的方法实际上是维护了一个滑动窗口,窗口内的都是没有重复的字符,我们需要尽可能的扩大窗口的大小。由于窗口在不停向右滑动,所以我们只关心每个字符最后出现的位置,并建立映射。窗口的右边界就是当前遍历到的字符的位置,为了求出窗口的大小,我们需要一个变量left来指向滑动窗口的左边界,这样,如果当前遍历到的字符从未出现过,那么直接扩大右边界,如果之前出现过,那么就分两种情况,在或不在滑动窗口内,如果不在滑动窗口内,那么就没事,当前字符可以加进来,如果在的话,就需要先在滑动窗口内去掉这个已经出现过的字符了,去掉的方法并不需要将左边界left一位一位向右遍历查找,由于我们的HashMap已经保存了该重复字符最后出现的位置,所以直接移动left指针就可以了。我们维护一个结果res,每次用出现过的窗口大小来更新结果res,就可以得到最终结果了。

代码
C++

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
       vector<int> m(256,-1);
        int res = 0, left = -1;
        for(int i = 0; i < s.size(); ++i)
        {
            left = max(left, m[s[i]]);
            m[s[i]] = i;
            res = max(res, i - left);
        }
        return res;
    }
};

python

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        res = 0
        List = []
        for i in s:
            if i not in List:
                List.append(i)
                res = max(res, len(List))
            else:
                index = List.index(i)
                List.append(i)
                List = List[index+1:]
        return res

以上是关于leetcode1-3题解的主要内容,如果未能解决你的问题,请参考以下文章

微信小程序代码片段

VSCode自定义代码片段——CSS选择器

谷歌浏览器调试jsp 引入代码片段,如何调试代码片段中的js

片段和活动之间的核心区别是啥?哪些代码可以写成片段?

VSCode自定义代码片段——.vue文件的模板

VSCode自定义代码片段6——CSS选择器