Part1-算法

96 阅读5分钟

7月14日--LeetCode

1.两数之和

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。==但是,数组中同一个元素在答案里不能重复出现。==

你可以按任意顺序返回答案。

给定nums = [2,7,11,15] target = 9

方法一:暴力枚举

思路及算法

最容易想到的方法是枚举数组中的每一个数x,寻找数组中是否存在target - x

当我们使用遍历整个数组的方式寻找target - x,需要注意到每一个位于x之前的元素都已经和x匹配过,因此不需要再进行匹配。而每一个元素不能被使用两次,所以我们只需要再x后面的元素寻找target -x

class Solution:
    def twoSum(self,nums:List[int],target:int) -> List[int]:
        n = len(nums)
        for i in range(n):
            for j in range(i + 1 , n ):
                if nums[i] + nums[j] == target:
                    return [i,j]

方法二:哈希表

注意到方法一的时间复杂度较高的原因是寻找target - x的时间,因此需要更优秀的办法

class Solution2:
    def twoSum(self,nums:List[int],target:int) -> List[int]:
        hashtable = dict()
        for i , num in hashtable :
            if target - num in hashtable:
                return [hashtable[target-num],i]
            hashtable[nums[i]] = i
        return []

175.组合两个表

表: Person

+-------------+---------+
| 列名         | 类型     |
+-------------+---------+
| PersonId    | int     |
| FirstName   | varchar |
| LastName    | varchar |
+-------------+---------+
personId 是该表的主键(具有唯一值的列)。
该表包含一些人的 ID 和他们的姓和名的信息。

表: Address

+-------------+---------+
| 列名         | 类型    |
+-------------+---------+
| AddressId   | int     |
| PersonId    | int     |
| City        | varchar |
| State       | varchar |
+-------------+---------+
addressId 是该表的主键(具有唯一值的列)。
该表的每一行都包含一个 ID = PersonId 的人的城市和州的信息。

编写解决方案,报告 Person 表中每个人的姓、名、城市和州。如果 personId 的地址不在 Address 表中,则报告为 null

任意顺序 返回结果表。

结果格式如下所示。

示例 1:

输入: 
Person表:
+----------+----------+-----------+
| personId | lastName | firstName |
+----------+----------+-----------+
| 1        | Wang     | Allen     |
| 2        | Alice    | Bob       |
+----------+----------+-----------+
Address表:
+-----------+----------+---------------+------------+
| addressId | personId | city          | state      |
+-----------+----------+---------------+------------+
| 1         | 2        | New York City | New York   |
| 2         | 3        | Leetcode      | California |
+-----------+----------+---------------+------------+
输出: 
+-----------+----------+---------------+----------+
| firstName | lastName | city          | state    |
+-----------+----------+---------------+----------+
| Allen     | Wang     | Null          | Null     |
| Bob       | Alice    | New York City | New York |
+-----------+----------+---------------+----------+
解释: 
地址表中没有 personId = 1 的地址,所以它们的城市和州返回 null。
addressId = 1 包含了 personId = 2 的地址信息。
import pandas as pd
def combine_two_tables(person:pd.DataFrame,address:pd.DataFrame) -> pd.DataFrame:
    combined = person.merge(address,on='personId',how='left')
    columns = ['firstName','lastName','city','state']
    combined = combined[columns]
    return combined

7月15日--LeetCode

P9.回文数

给一个整数X,如果X是一个回文整数,返回true;否则,返回false

==回文数==是指正序(从左向右)和倒叙(从右向左)读都是一样的整数

实例1:

​ 输入 x = 121

​ 输出 true

实例2:

​ 输入 x = -121

​ 输出false

class Solution:
    def ifPalindrome(self,x:int) -> bool:
        num_str = str(x)
        return num_str == num_str[::-1]
class Solution {
    public boolean ifPalindrome(int x){
        //特殊情况
        //如上所述,当x < 0 时,x不是回文数
        //同样地 如果数字的最后一位是0,为了使该数字为回文,则第一位数字也应该是0
        //只有0满足这一属性
        if(x < 0 || ((x & 10) == 0 && x != 0)){
            return false;
        }

        int revertedNumber = 0;
        while (x > revertedNumber){
            revertedNumber = revertedNumber * 10 + x % 10;
            x /= 10;
        }
        return x == revertedNumber || x == revertedNumber / 10;
    }
}
//双向指针
class Solution_ {
    public boolean isPalindrome(int x){

        if ( x < 0 || (x % 10 ==0 && x !=0)){
            return false;
        }

        String str = Integer.toString(x);

        int right = 0,left = str.length() - 1;
        while (right < left){
            if(str.charAt(right) != str.charAt(left)){
                return false;
            }
            left --;
            right ++;
        }
        return true;
    }
}

P721.账户合并

给定一个列表 accounts,每个元素 accounts[i] 是一个字符串列表,其中第一个元素 accounts[i][0]名称 (name),其余元素是 emails 表示该账户的邮箱地址。

现在,我们想合并这些账户。如果两个账户都有一些共同的邮箱地址,则两个账户必定属于同一个人。请注意,即使两个账户具有相同的名称,它们也可能属于不同的人,因为人们可能具有相同的名称。一个人最初可以拥有任意数量的账户,但其所有账户都具有相同的名称。

合并账户后,按以下格式返回账户:每个账户的第一个元素是名称,其余元素是 按字符 ASCII 顺序排列 的邮箱地址。账户本身可以以 任意顺序 返回。

官方题解:

​ 方法一:哈希表+并查集

​ 两个账户需要合并,当且仅当两个账户至少有一个共同的邮箱地址,因此这道题的实质是判断所有的邮箱地址中有哪些邮箱地址必定属于同一人,可以使用并查集实现。

import collections
from typing import List
class UnionFind:
    def __init__(self,n):
        self.parent = list(range(n))
    
    def union(self,index1 : int,index2 :int):
        self.parent[self.find(index2)] = self.find(index1)
        
    def find(self,index:int) -> int:
        if self.parent[index] != index:
            self.parent[index] = self.find(self.parent[index])
        return self.parent[index]
class Solution:
    def accountsMerge(self,accounts : List[List[str]]) -> List[List[str]]:
        emailToIndex = dict()
        emailToName = dict()
        
        for account in accounts:
            name = account[0]
            for email in account[1:]:
                if email not in emailToIndex:
                    emailToIndex[email] = len(emailToIndex)
                    emailToName[email] = name
        uf = UnionFind(len(emailToIndex))
        for account in accounts:
            firstIndex = emailToIndex[account[1]]
            for email in account[2:]:
                uf.union(firstIndex,emailToIndex[email])
            
        indexToEmails = collections.defaultdict(list)
        
        for email,index in emailToIndex.items():
            index = uf.find(index)
            indexToEmails[index].append(email)
            
        ans = list()
        for emails in indexToEmails.values():
            ans.append([emailToName[emails[0]]] + sorted(emails))
        return ans

1.构建哈希映射 ("邮箱" -> "所属用户"),然后遍历映射,把同一个邮箱的用户编号用查并查集合并起来

2.再构建有序映射"用户编号" -> 邮箱比那好(有序集合), 遍历用户编号[0,n),把每个用户的邮箱加入到find(i) 的邮箱集合中。

3.最后把上面那个有序映射转成二维数组返回即可