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:
一次遍历法。需要满足两个条件:
- 车总是可以从i开到i+1;
- 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;
}