LeetCode刷题——190323

Candy

题目:

有n个孩子排成一排,为每个孩子分配一个等级。你分配给这些孩子的糖果需要符合以下要求:1.每个孩子至少要有一颗糖果;2.等级高的孩子要比他们的邻居得到更多的糖果。你最少需要给多少颗糖果。

思路:

遍历两遍。先从左往右遍历,再从右往左.我的思路只想到了一个方向上的扫描,不能保证双向最大
必须保证大于左右节点(双向)的等级,candy[i]最大,所以要双向扫描

代码:



  public int candy(int[] ratings) {
     if(ratings.length==1) return 1;
     int[] candy = new int[ratings.length];
     int res = 0;
     Arrays.fill(candy, 1);//填充序列
     for(int i=1;i<ratings.length;++i) {
        if(ratings[i]>ratings[i-1])
            candy[i]=candy[i-1]+1;
     }       
     for(int i = ratings.length-1;i>=1;--i) {
        if(ratings[i]<ratings[i-1] && candy[i]>=candy[i-1])
            candy[i-1]=candy[i]+1;
     }
     for(int i:candy)
        res +=i;
        return res;
    }




Gas-station

题目:

沿环形路线有n个加油站,其中第i个加油站的天然气量为gas[i]。你有一辆没有限制油箱的车,从第i站到第i+1站需要消耗cost[i]汽油。你从某一个加油站的空油箱出发。如果你能绕着电路走一圈,返回出发时的加油站那么就输出这个出发时加油站的序号i,否则返回-1。
该解决方案保证是唯一的。

思路1:

贪心算法/两次遍历法。(时间复杂度O(n2)关键步骤:leave = leave+gas[i]-cost[i]>0
遇到难题:对于循环数组的处理 k=(i+j)%length;//i表示起点,j表示距离起点的间隔数!

代码:

public int canCompleteCircuit(int[] gas, int[] cost) {
        if(gas.length!=cost.length || gas.length <1)
           return -1;
     int length = gas.length;
     for(int i=0;i<length;++i) {
        int leave = 0;
        for(int j=0;j<length;++j) {
               int k = (i+j)%length;//循环数组的取法。
               leave = leave + gas[k]- cost[k];
               if( leave>=0 && j==length-1 )
                   return i;
               else if(leave<0)
                   break;
        }
     }
        return -1;
    }

思路2:

一次遍历法。需要满足两个条件:

  1. 车总是可以从i开到i+1;
  2. gas的和大于cost的和
    那么,假设从编号为0站开始,一直到k站都正常,在开往k+1站时车子没油了。这时,应该将起点设置为k+1站。
    问题1: 为什么应该将起始站点设为k+1?
    因为k->k+1站耗油太大,0->k站剩余油量都是不为负的,每减少一站,就少了一些剩余油量。所以如果从k前面的站点作为起始站,剩余油量不可能冲过k+1站。
    问题2: 为什么如果k+1->end全部可以正常通行,且rest>=零就可以说明车子从k+1站点出发可以开完全程?
    因为,起始点将当前路径分为A、B两部分。其中,必然有A部分剩余油量<0。B部分剩余油量>0。
    所以,无论多少个站,都可以抽象为两个站点(A、B)。从B站加满油出发,开往A站,车加油,再开回B站的过程。
    重点:B剩余的油>=A缺少的总油。必然可以推出,B剩余的油>=A站点的每个子站点缺少的油。

代码:

   public int canCompleteCircuit(int[] gas, int[] cost) {
        if(gas.length!=cost.length || gas.length <1)
            return -1;
        int total = 0,run =0, start =0;
        for(int i=0;i<gas.length;++i) {
         run =run+gas[i]-cost[i]; //本次消耗
         total= total+gas[i]-cost[i]; //总消耗
         if(run<0) {
            start = i+1;//解的位置
            run = 0;
         }
        }
        return total<0?-1:start; //只要total>0,肯定存在一个解
    }




Leetcode133克隆图

题目:

给定无向连通图中一个节点的引用,返回该图的深拷贝(克隆)。图中的每个节点都包含它的值 val(Int) 和其邻居的列表(list[Node])
在这里插入图片描述

思路1:

深度优先遍历(递归)。针对每个节点进行操作

代码:

https://www.cnblogs.com/grandyang/p/4267628.html

    Map<Node,Node> map = new HashMap<>();
    public Node cloneGraph(Node node) {
     if(node == null) return null;
     List<Node> l =new ArrayList<>();
     Node res = new Node(node.val,l); //res为节点node 的一个复制,先进行值的复制
     Node newHead = res;// 判断该点在不在map中,如果不在,就加进去(本题中,节点值都不同)
     if(!map.containsKey(node))
        map.put(node, res);
// 开始对节点node的邻居节点进行复制。复制之前,首先要保证邻居节点已经被复制,所以就调用递归
     for(Node n :node.neighbors) {
        if(map.containsKey(n)) //如果在map中已经存放过这个节点,那么直接加入res的邻居节点域
            l.add(map.get(n));
        else
            l.add(cloneGraph(n)); //否则递归的对这个节点进行克隆图,即添加到map中,然后再放入邻居
     }
       return res;
    }

猜你喜欢

转载自blog.csdn.net/weixin_39345957/article/details/88958988