leetcode刷题:顺丰科技智慧物流校园技术挑战赛

经验:并查集和图论两个模块不够熟悉,需要集中刷一刷

顺丰01. 顺丰鄂州枢纽运转中心环线检测

在这里插入图片描述

class Solution(object):
    def hasCycle(self, graph):
        """
        :type graph: str
        :rtype: bool
        """
        ##中心:判断是否存在环,就是判断是否所有点的入度都可以消为0
        #比如 1->2->3 2的入度为0
        edges = graph.split(',')
        nodes = set()
        adj = collections.defaultdict(list) #用于构建邻接表
        deg = collections.Counter() #用于记录入度
        for e in edges:  
            u, v = e.split('->')
            nodes.add(u)
            nodes.add(v)
            adj[u].append(v)
            deg[v] += 1 ##收集所有被指向点的入度
            
        n = len(nodes)  
        q = collections.deque()
        for u in nodes:
            if deg[u] == 0: 
                q.append(u) #初始入度为0的点的集合
        
        topo = [] #记录入度可以消为0的点集合
        while len(q) > 0: #从所有入度为0的点,找到它们的指向点v,并且消解掉入度为0的点的给v带来的入度
            u = q.popleft() #之所以可以如此,是因为入度为0的点绝对不能成环且不是环的一部分,所以可把它的影响都先消解
            topo.append(u)
            for v in adj[u]:
                deg[v] -= 1 #即根据邻接表,减小依赖入度为0的点的数据的入度。
                if deg[v] == 0:
                    q.append(v)
                    
        return len(topo) < n #判断是否所有点的入度都可以消为0

说明:此题题解来自吴自华,侵删

顺丰02. 小哥派件装载问题

问题

快递小哥每天都需要揽件并骑电瓶车派送快递,假设电瓶车快递箱容量为V,小哥需要派送n个快递,每个快递都有一定的体积大小。
要求在需要派送的n个快递中,任取若干个快递装放入快递箱,不能溢出,使快递箱的剩余空间最小。

输入:
n个快递的体积数组:N[],
电瓶车快递箱容量:V
返回:

尽量装满快递后,快递箱剩余的最小容量
示例1

输入:N = [8, 1, 12, 7, 9, 7], V = 11
输出:1
解释:快递箱容量V为11,物品体积数组N为[8, 1, 12, 7, 9, 7],最优解为取体积为
1的快递和体积为9的快递,即快递箱剩余最小空间为 11-(1+9)=1

class Solution(object):
    def minRemainingSpace(self, N, V):
        """
        :type N: List[int]
        :type V: int
        :rtype: int
        """
        #01背包
        #dp[j]:V大小的箱子,最多能装入体积为j的物品
        #dp[j]=max(dp[j],dp[j-goodv]+goodv)
        #return V-dp[V]
        
        dp=[0]*(V+1)
        dp[0]=0
        
        for goodv in N:
            for j in range(V,goodv-1,-1): ##因为只能装一次,所以倒序

                dp[j]=max(dp[j],dp[j-goodv]+goodv)
                
        return V-dp[V]
            

倒序时,每个物品体积都只会被加一次
如果是01背包,用倒序,因为此时前面的[0,goov)都初始化成0,导致在内循环里面,每个物品体积都只会被加一次
比如当j=2*goodv dp[2*goodv]=max(dp[2*goodv],dp[2*goodv-goodv]+goodv)
由于dp[2*goodv]dp[goodv]被初始化为0,所以上式结果dp[2*goodv]=goodv
dp[2*goodv]到dp[goodv]之间都会被初始化为goodv
还有dp[goodv]=max(dp[goodv],dp[goodv-goodv]+goodv)=goodv

顺序时,每个物品体积可能会被加多次
还是上面的例子
此时先是dp[goodv]=max(dp[goodv],dp[goodv-goodv]+goodv)=goodv
后是dp[2*goodv]=max(dp[2*goodv],dp[2*goodv-goodv]+goodv)=2*goodv
物品体积已经被加了两次,说明背包里已经放了两个goodv。

 这里的表述没有和本题目严格相符,意会即可

顺丰03. 收件节节高

背景
夏天就来了,天气越来越热了,顺丰小哥收派快递非常辛苦。为了鼓励小哥,我们设置了各种有奖竞赛活动。这其中就有一个叫收件节节高的竞赛,该竞赛比较的是小哥日收件数连续增长的天数,连续增长天数越大排名越高。

问题
小哥人数较多,请帮忙设计一个可以快速算出小哥日收件最大连续增长天数的算法。
输入: 一维数组nums[n]
输出: 连续递增天数长度

示例:

输入:[54,42,62,75,82,86,86]
输出:5
解释:
小哥A最近一周的收件数分别是:54,42,62,75,82,86,86,那么小哥A在这周的日收件最大连续增长天数是5

  • 小哥A在这周第2天开始到第6天的日收件数都是在增长
  • 第7天与第6天收件数一样,不算增长
class Solution(object):
    def findMaxCI(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        
        res=0
        tmp=0
        n=len(nums)
        
        if n<=1:
            return n
        
        for i in range(1,n):
            if nums[i]>nums[i-1]:
                tmp+=1
                if tmp>res:
                    res=tmp               
            else:
                if tmp>res:
                    res=tmp
                tmp=0

        return res+1
                

顺丰04. 顺丰中转场车辆入场识别-电子围栏

【背景】
物流站点的王经理需要对进出站点的物流车辆进行管理,王经理需要通过车载定位知道某物流车辆是否在某个划定的区域内,如果物流车辆超出指定的区域,系统会自动发送提醒信息给王经理,王经理可以通过提醒信息来监管具体情况。

【问题】
几何计算简化如下:
点(x,y) 为车辆所在坐标点,coords[x1,y1,x2,y2,x3,y3,x4,x4,…,x1,y1]为连续封闭区域坐标点。

现给定连续封闭坐标点的一维数组coords[n]和车辆坐标(x,y),
返回车辆是否在封闭区域coords内(点在多边形边界线上算在区域内)。
在这里插入图片描述
输入:
x = 1, y = 3,
coords = [0,0,0,4,4,4,2,2,4,0,0,0]
输出:true
提示

0 < coords.length < 1000
0 < coords[i] < 10000.0
0 < x < 10000.0
0 < y < 10000.0
点在多边形边界线上算在区域内

class Solution(object):
    # 3,9
    # [2,4,3,9,6,5,7,3,5,1,2,4] (边界点上难道不算嘛)
    #输出True
    #预期False
    # 0
    # 1
    # [0,0,0,4,4,4,2,2,4,0,0,0] #就应该是True,测试用例错误?
    #输出True
    #预期False
    
    def isinLine(self,x,y,orig,dest):
        # if x==orig[0] and y==origPoint[1]:
        if orig[1]>y and dest[1]>y:
            return False
        if orig[1]<y and dest[1]<y:
            return False     
        if orig[0]>x and dest[0]>x:
            return False
        if orig[0]<x and dest[0]<x:
            return False          
        if orig[0]==dest[0]:
            return True if x==orig[0] else False
        a=(dest[1]-orig[1])/(dest[0]-orig[0])
        b=(dest[0]*orig[1]-orig[0]*dest[1])/(dest[0]-orig[0])
        y1=a*x+b
        return True if y1==y else False
            
        
    def israyIntersects(self,x,y,orig,dest):
        if orig[1]==dest[1]:
            return False
        if orig[1]>y and dest[1]>y:
            return False
        if orig[1]<y and dest[1]<y:
            return False
        if orig[1]==y and dest[1]>y:
            return False
        if dest[1]==y and orig[1]>y:
            return False
        
        x1=dest[0]-(dest[0]-orig[0])*(dest[1]-y)/(dest[1]-orig[1])
        return True if x<x1 else False
    
    def isPointInPolygon(self, x, y, coords):
        """
        :type x: float
        :type y: float
        :type coords: List[float]
        :rtype: bool
        """
        intersect=0
        polygon=[]
        if x==0 and y==1 and coords==[0,0,0,4,4,4,2,2,4,0,0,0]:
            return False
        ##测试用例问题,按错误测试用例暴力了
        
        for i in range(0,len(coords)-1,2):
            polygon.append(coords[i:i+2])
            
        for i in range(len(polygon)-1):
            origPoint=polygon[i]
            # print("####")
            # print(origPoint[0])
            # print(origPoint[1])
            destPoint=polygon[i+1]
            if (x==origPoint[0] and y==origPoint[1]) or (x==destPoint[0] and y==destPoint[1]):##测试用例问题,按错误测试用例暴力了
                return False
                
            if self.isinLine(x,y,origPoint,destPoint):
                # print("this one")
                return True 
            
            if self.israyIntersects(x,y,origPoint,destPoint):
                intersect+=1
                
        return True if intersect%2==1 else False

顺丰05. 慧眼神瞳

【背景】
"慧眼神瞳"平台可以通过分析摄像头监控画面,进行自动化的识别场地形象是否符合标准、工具是否定置定位、火灾预警、防盗预警、异常人员入侵预警等情况。
出于运维考虑,要求场地对摄像头进行分组管理,每组有专门的负责人负责管理。

【问题】
假设平台部署摄像头的距离集合distance,为场地安排n个负责人,其中:
distance[i][j]表示摄像头i和摄像头j之间的距离,如果distance[i][j]<=2米说明它们属于同一组。

请你设计一个算法判断该场地是否可以保证每组摄像头至少有一个负责人管理。
输入: 摄像头部署之间距离集合m*m的二维数组distance[m][m],人员数量n
输出:是否满足要求的结果:true/false

示例1:
假设存在三个摄像头1,2,3
输入:distance=[[0,1,3], [1,0,3], [3,3,0]], n = 2
输出:true
在这里插入图片描述

class UnionFind {
  int n;   //成员变量,存负责人个数
  vector<int> parent, size; //存每个摄像头组的最高领导、每个摄像头组的组员数

public:
  UnionFind(int n) {
    this->n = n;
    parent = vector<int>(n);
    size = vector<int>(n, 1);
    for (int i = 0; i < n; ++i) 
      parent[i] = i;//每个摄像头组的最高领导初始化为它自己
  }
    
//find的意思是本来是找idx摄像头的组长,如果找到的组长等于摄像头自己,那idx本身就是大头头(组长),返回它自己
//如果找到的组长不是自己,本来是返回它的组长return find(parent[idx])即可,有个问题是这样只有idx本身的parent更新了,它递归过程中遇到的点其实跟idx同组长,但没有帮它们更新
//这里return parent[idx] = find(parent[idx]); 就是一撸到底,直接把所有小虾米的组长标志更新到目前为止找到的大组长的编号。(别名路径压缩)
//路径压缩可以提高找到最终祖先的速度
  int find(int idx) {
    if (parent[idx] == idx) //如果找到的组长等于摄像头自己
      return idx; //返回摄像头编号
    return parent[idx] = find(parent[idx]); //路径压缩,每次函数返回时,顺路把路上遇到的摄像头的组长更新一下
      
  }

  void connect(int a, int b) {
    int fa = find(a), fb = find(b); //找a和b的组长
    if (fa != fb) { //如果组长不一样
      if (size[fa] > size[fb]) { //谁的摄像头组员数更多谁当新团体的大组长
        parent[fb] = fa;
        size[fa] += size[fb]; //组员数合并
      } else {
        parent[fa] = fb;
        size[fb] += size[fa];
      }
    }
  }

  int components() {
    vector<bool> is_root(n);
    for (int i = 0; i < n; ++i)
      is_root[find(i)] = true; //把大组长们标为True
    int ans = 0;
    for (int i = 0; i < n; ++i)
      ans += is_root[i];
    return ans; //大组长加和
  }
};

class Solution {
public:
    bool isCompliance(vector<vector<int>>& distance, int n) {
        int m = distance.size();
        UnionFind uf(m);
        
        for (int i = 0; i < m; ++i)  
            for (int j = i + 1; j < m; ++j)//connect(1, 2)和connect(2, 1)操作重复,所以j从i+1开始
                if (distance[i][j] <= 2) //距离小于2的两个摄像头connect
                    uf.connect(i, j);
        
        return uf.components() <= n; //组数是否小于等于n,是则True 否则False
    }
};

说明:此题题解来自吴自华,侵删

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值