Algorithm 排列花盆的数量
这是一个谷歌面试问题。这里只有一个T和F的列表。All表示一个位置,T表示该位置被一个花盆占据,F表示花盆不在那个里,所以你们可以在这个位置放置另一个花盆。找出在给定排列中可以放置的罐的数量,这样就不会有两个罐彼此相邻——它们可以在给定排列中相邻。如果开始的位置未被占用,则如果第二个位置也未被占用,则可以放置锅;如果最后一个位置未被占用,则如果第二个位置也未被占用,则可以放置锅。例如 TFFFTFFFT-返回2 FFTTFFFTTFF-返回4Algorithm 排列花盆的数量,algorithm,dynamic-programming,Algorithm,Dynamic Programming,这是一个谷歌面试问题。这里只有一个T和F的列表。All表示一个位置,T表示该位置被一个花盆占据,F表示花盆不在那个里,所以你们可以在这个位置放置另一个花盆。找出在给定排列中可以放置的罐的数量,这样就不会有两个罐彼此相邻——它们可以在给定排列中相邻。如果开始的位置未被占用,则如果第二个位置也未被占用,则可以放置锅;如果最后一个位置未被占用,则如果第二个位置也未被占用,则可以放置锅。例如 TFFFTFFFT-返回2 FFTTFFFTTFF-返回4 我试图通过查看每个位置的相邻值来解决这个问题。如果两
我试图通过查看每个位置的相邻值来解决这个问题。如果两个相邻位置都是F,则增加计数器,并将此位置设置为T。我需要更好的解决方案或任何其他解决方案(如果有)。我会这样处理问题。您需要FFF再增加一个罐,FFFFF再增加两个罐,等等。要处理末端案例,请在每一端添加一个F 因为这非常类似于16位整数,所以该算法应该使用二进制算术运算之类的技巧 这里是一个Python实现,它使用位掩码值&1、位移位值>>=1和数学零-1/2来计算空槽数并计算可以容纳多少花盆
#value = 0b1000100100001
value = 0b0011000001100
width = 13
print bin(value)
pots = 0 # number of flower pots possible
zeros = 1 # number of zero bits in a row, start with one leading zero
for i in range(width):
if value & 1: # bit is one, count the number of zeros
if zeros > 0:
pots += (zeros - 1) / 2
zeros = 0
else: # bit is zero, increment the number found
zeros += 1
value >>= 1 # shift the bits to the right
zeros += 1 # add one trailing zero
pots += (zeros - 1) / 2
print pots, "flower pots"
您可以使用修改后的Mergesort来执行此操作。考虑可以放置在单体中的花盆,然后可以放置在双子座中的花盆合并这些单体,在树上排列成完整的排列。它将在lg n上完成n个花盆的列表 当然有一种方法可以做到这一点,它是一种复杂度为^2的改进棒切割算法。子问题是所考虑的子字符串中是否存在开放的假集合。闭合的false集合已经为它们计算了一些最大值。因此,当添加新角色时,它要么增加可插入的花盆数量,要么锁定子字符串可用花盆的最大数量 此外,您知道,如果仅在一侧用括号括起来,那么在一组由闭合位置绑定的n个开放位置中可以放置的最大花盆数为n-2,否则为n-1,即,字符串以假集合开始或结束。到达第二个花盆时,可计算第一个位置打开或关闭的基本条件 因此,我们可以根据先前计算出的可插入较小分区的最大花盆数量,累积到可插入整个布局的花盆总数。通过将以前的计算存储在一个数组中,我们将计算下一个子数组的最大值所需的时间减少到单个数组查找和一些恒定时间计算。这就是动态规划的本质
编辑:我更新了答案以提供动态编程方法的描述。请考虑通过我在评论中提到的互动教材! 让我们分析一下必须做什么 因此,首先我们可能需要参观和考察每个地方。这意味着某种循环。例如:
for (int i = 0; i < myPlaces.Length; ++i)
但这还不足以把花盆放在那里。我们必须检查下一个和上一个地方是否有空
place[i-1]
place[i+1]
如果所有的树都含有F,你可以把花盆放在那里,然后移到下一块地
现在,我们也有一些例外。列表的开头和结尾。所以你必须单独处理它们。例如
if (i == 0)
{
// only check current position and next position
}
if (i == myPlaces.Length - 1) // minus 1 because indexing usually starts from 0
{
// only check current position and previous position
}
之后,您可以执行前面提到的检查
现在让我们考虑一下输入数据。一般来说,不修改输入数据是一个好习惯,而是制作一份副本并处理副本。此外,对于不同的任务,某些数据结构比其他数据结构工作得更好。在这里,您可以使用简单的字符串来保存输入值。但是我想说一个字符数组会是一个更好的选择,因为当你找到一个可以放置花盆的地方时,你实际上可以用数组中的T替换F。然后,当您移动到新位置时,您的数据结构器知道在前一位置已经有一个pot,因此您的算法不会放置相邻的pot。
因为字符串是不可变的,所以不能使用字符串来实现这一点,并且每次都需要生成一个新字符串
请注意,这只是一个幼稚的算法,有很多改进和优化的余地。但我的目标是给出一些解决这类问题的方法。在谷歌找工作之前,我将把这些细节留给你作为下午的练习 解决方案非常简单,检查位置的先前值和当前值,将位置标记为可种植或可推杆,并增加计数。读取下一个值(如果已种植),回溯并更改上一个值和d 请原谅伯爵。复杂性正在显现。我们真正想要检查的是1001的出现。下面是该算法在Java中的实现
public boolean canPlaceFlowers(List<Boolean> flowerbed, int numberToPlace) {
Boolean previous = false;
boolean puttable = false;
boolean prevChanged = false;
int planted = 0;
for (Boolean current : flowerbed) {
if (previous == false && current == false) {
puttable = true;
}
if (prevChanged == true && current == true) {
planted--;
}
if (puttable) {
previous = true;
prevChanged = true;
planted++;
puttable = false;
} else {
previous = current;
prevChanged = false;
}
}
if (planted >= numberToPlace) {
return true;
}
return false;
}
private static void canPlaceOneFlower(List<Boolean> flowerbed, FlowerBed fb) {
boolean result;
result = fb.canPlaceFlowers(flowerbed, 1);
System.out.println("Can place 1 flower");
if (result) {
System.out.println("-->Yes");
} else {
System.out.println("-->No");
}
}
private static void canPlaceTwoFlowers(List<Boolean> flowerbed, FlowerBed fb) {
boolean result;
result = fb.canPlaceFlowers(flowerbed, 2);
System.out.println("Can place 2 flowers");
if (result) {
System.out.println("-->Yes");
} else {
System.out.println("-->No");
}
}
private static void canPlaceThreeFlowers(List<Boolean> flowerbed, FlowerBed fb) {
boolean result;
result = fb.canPlaceFlowers(flowerbed, 3);
System.out.println("Can place 3 flowers");
if (result) {
System.out.println("-->Yes");
} else {
System.out.println("-->No");
}
}
private static void canPlaceFourFlowers(List<Boolean> flowerbed, FlowerBed fb) {
boolean result;
result = fb.canPlaceFlowers(flowerbed, 4);
System.out.println("Can place 4 flowers");
if (result) {
System.out.println("-->Yes");
} else {
System.out.println("-->No");
}
}
public static void main(String[] args) {
List<Boolean> flowerbed = makeBed(new int[] { 0, 0, 0, 0, 0, 0, 0 });
FlowerBed fb = new FlowerBed();
canPlaceFourFlowers(flowerbed, fb);
canPlaceThreeFlowers(flowerbed, fb);
flowerbed = makeBed(new int[] { 0, 0, 0, 1, 0, 0, 0 });
canPlaceFourFlowers(flowerbed, fb);
canPlaceThreeFlowers(flowerbed, fb);
canPlaceTwoFlowers(flowerbed, fb);
flowerbed = makeBed(new int[] { 1, 0, 0, 1, 0, 0, 0, 1 });
canPlaceFourFlowers(flowerbed, fb);
canPlaceThreeFlowers(flowerbed, fb);
canPlaceTwoFlowers(flowerbed, fb);
canPlaceOneFlower(flowerbed, fb);
}我的解决方案使用动态规划 ar是以['F','T','F']形式表示的数组
import numpy as np
def pot(ar):
s = len(ar)
rt = np.zeros((s,s))
for k in range(0,s):
for i in range(s-k):
for j in range(i,i+k+1):
left = 0
right = 0
if ar[j] != 'F':
continue
if j-1 >= i and ar[j-1] == 'T':
continue
else:
left = 0
if j+1 <= i+k and ar[j+1] == 'T':
continue
else:
right = 0
if j-2 >= i:
left = rt[i][j-2]
if j+2 <= i+k:
right = rt[j+2][i+k]
rt[i][i+k] = max(rt[i][i+k], left+right+1)
return rt[0][len(ar)-1]
我的解决方案是用C写的
private static int CheckAvailableSlots(string str)
{
int counter = 0;
char[] chrs = str.ToCharArray();
if (chrs.FirstOrDefault().Equals('F'))
if (chrs.Length == 1)
counter++;
else if (chrs.Skip(1).FirstOrDefault().Equals('F'))
counter++;
if (chrs.LastOrDefault().Equals('F') && chrs.Reverse().Skip(1).FirstOrDefault().Equals('F'))
counter++;
for (int i = 1; i < chrs.Length - 2; i++)
{
if (chrs[i - 1].Equals('T'))
continue;
else if (chrs[i].Equals('F') && chrs[i + 1].Equals('F'))
{
chrs[i] = 'T';
counter++;
i++;
}
else
i++;
}
return counter;
}
如果你想得到一份软件工作,这确实是你应该能够自己解决的事情。他们会改变面试问题,你需要展示对问题背后的CS原则的了解,而不仅仅是解决方案。StackExchange不是学习的替代品。从这里开始:@user2357112,问题不在于如何找到一份工作。我需要一个解决这个问题的方向,或者一个我还不知道的概念。对于我来说,这听起来是一个有效的问题,请你提出建议。这和我在问题末尾提到的方法不一样吗。我需要处理拐角处的情况。我的意思是我扫描列表中的每个元素。对于每个元素,我都会相应地检查相邻元素和递增计数器。我将在索引0和list.size-1处设置角点条件,并分别处理它们。很抱歉回复太长。希望有人阅读你的问题,可以受益于更透彻的解释。至于转角情况,您可以显式执行,因此检查它是否为0索引。如果是,只检查下一个位置和当前位置。如果是最后一次-检查上一次和当前。然后,如果这两种情况都不是,则执行进一步的检查-这样可以避免索引超出范围异常。还可以单独检查total的长度是否不只是1。其他方法将如布伦特·沃什伯恩所建议的那样。只有这样,才记得从1开始迭代,并在长度-1结束,但不需要边情况
private static int CheckAvailableSlots(string str)
{
int counter = 0;
char[] chrs = str.ToCharArray();
if (chrs.FirstOrDefault().Equals('F'))
if (chrs.Length == 1)
counter++;
else if (chrs.Skip(1).FirstOrDefault().Equals('F'))
counter++;
if (chrs.LastOrDefault().Equals('F') && chrs.Reverse().Skip(1).FirstOrDefault().Equals('F'))
counter++;
for (int i = 1; i < chrs.Length - 2; i++)
{
if (chrs[i - 1].Equals('T'))
continue;
else if (chrs[i].Equals('F') && chrs[i + 1].Equals('F'))
{
chrs[i] = 'T';
counter++;
i++;
}
else
i++;
}
return counter;
}