在安排中编号花盆
Posted
技术标签:
【中文标题】在安排中编号花盆【英文标题】:Number flower pots in an arrangement 【发布时间】:2015-08-03 16:04:31 【问题描述】:这是一个谷歌面试问题。只有“T”和“F”的列表。 All 表示一个位置,T 表示该位置被花盆占据,F 表示花盆不在,因此您可以在该位置放置另一个花盆。找出可以放置在给定排列中的锅的数量,使得没有两个锅彼此相邻(它们可以在给定的排列中相邻)。如果一开始的位置未被占用,则如果第二个位置也未被占用,则可以放置一个罐子,如果最后一个位置未被占用,则如果倒数第二个位置也未被占用,则可以放置一个罐子。例如。
TFFFTFFTFFFFT - 返回 2 FFTTFFFFFTTFF - 返回 4
我尝试通过查看值为 F 的每个位置的相邻值来解决它。如果两个相邻位置均为 F,则增加计数器并将此位置设置为 T。我需要更好的解决方案或任何其他解决方案(如果有)。
【问题讨论】:
如果你想得到一份软件工作,这真的应该是你自己能解决的。 他们会改变面试问题,你需要展示问题背后的 CS 原则知识,而不仅仅是解决方案。 StackExchange 不能替代学习。从这里开始:interactivepython.org/runestone/static/pythonds/index.html @user2357112,问题不在于如何找到工作。 我需要一个解决这个问题的方向或一个我还不知道的概念。 听起来对我来说是一个有效的问题 【参考方案1】:让我们分析一下必须要做的事情。
所以首先我们可能需要访问并检查每个地方。这表明某种循环。例如:
for (int i = 0; i < myPlaces.Length; ++i)
当我们在某个地点时,我们必须检查它是否被占用
if (place[i] == 'F')
但这还不足以将花盆放在那里。我们必须检查下一个和上一个地方是否免费
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
。然后,当您移动到新位置时,您的数据构造器知道先前位置已经有一个底池,因此您的算法不会放置相邻的底池。
您将无法使用字符串来执行此操作,因为字符串是不可变的,并且您每次都需要生成一个新字符串。
请注意,这只是一种天真的算法,有很大的改进和优化空间。但我的目标是给出一些想法,一般来说如何解决这类问题。我将把细节的实施留给你,作为一个下午的练习,然后再找一份 Google 的工作。
【讨论】:
感谢您的建议。是不是和我在问题结尾提到的方法类似。我需要处理角落状况。我的意思是我扫描列表中的每个元素。对于每个元素,我都会检查相邻元素并相应地增加计数器。我将在索引 0 和 list.size-1 处有角条件并分别处理它们。 抱歉回复太长了。希望阅读您的问题的人可以从更详尽的解释中受益。至于极端情况,您可以明确地执行此操作,因此请检查它是否为 0 索引。如果是这样,只检查下一个位置和当前位置。如果是最后一个 - 检查以前的和当前的。然后,如果这两种情况都不是,请执行进一步检查 - 这样您将避免索引超出范围异常。还单独检查总长度是否不仅仅是 1。其他方法将按照 Brent Washburne 的建议。只有这样才记得从 1 开始迭代并以 Length - 1 结束但不需要边缘情况【参考方案2】:您可以通过修改后的合并排序来做到这一点。考虑可以放置在单件中的花盆,然后将可以放置在双件中的花盆合并这些单件,向上到完整的排列。它将在O(n lg n)
中完成 n 个花盆的列表。
当然有一种方法可以使用复杂度 O(n^2)
的修改后的棒切割算法来做到这一点。子问题是正在考虑的子字符串中是否存在开放的“错误集”。 “封闭的错误集”已经为它们计算了一些最大值。因此,当添加一个新字符时,它要么增加可插入的花盆数量,要么“锁定”子字符串的最大可用花盆数量。
另外,你知道可以放置在一组 n 个由封闭仓位限制的开放仓位中的最大花盆是 n - 2(否则 n -1 如果仅在一侧加括号,即字符串以“假集合”开始或结束。基本条件(第一个位置打开,或第一个位置关闭)可以在到达第二个花盆时计算.
因此,我们可以根据可以插入较小的子排列的最大花盆数量来建立可以插入整个排列的花盆总数 em> 之前计算过的。通过将我们之前的计算存储在一个数组中,我们将计算下一个子排列的最大值所需的时间减少到单个数组查找和一些恒定时间计算。这就是动态规划的精髓!
编辑:我更新了答案以提供动态编程方法的描述。请考虑阅读我在 cmets 中提到的交互式教科书! http://interactivepython.org/runestone/static/pythonds/index.html
【讨论】:
【参考方案3】:我会这样处理问题。您需要 FFF 多一个罐子,FFFFF 两个罐子,等等。要处理末端情况,请在每一端添加一个 F。
因为这与 16 位整数非常相似,所以算法应该使用二进制算术运算等技巧。
这是一个 Python 实现,它使用位掩码 (value & 1
)、位移位 (value >>= 1
) 和数学 ((zeros - 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"
【讨论】:
【参考方案4】:解决方法真的很简单,检查位置的先前值和当前值并将位置标记为可种植(或可放置)并增加计数。读取下一个值,如果它已经被种植,(回溯和)更改前一个值并减少计数。复杂度为 O(n)。我们真正要检查的是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);
【讨论】:
【参考方案5】:我使用动态编程的解决方案。
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]
【讨论】:
【参考方案6】:我用 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;
【讨论】:
【参考方案7】:// 1='T'
// 0='F'
int[] flowerbed = new int[] 1,0,0,0,0,1;
public boolean canPlaceFlowers(int[] flowerbed, int n)
int tg = 0;
for (int i = 0, g = 1; i < flowerbed.length && tg < n; i++)
g += flowerbed[i] == 0 ? flowerbed.length - 1 == i ? 2 : 1 : 0;
if (flowerbed[i] == 1 || i == flowerbed.length - 1)
tg += g / 2 - (g % 2 == 0 ? 1 : 0);
g = 0;
return tg >= n;
【讨论】:
【参考方案8】:这些答案中的大多数(除非他们更改数组或遍历和复制)不考虑前 3 个(或最后 3 个)罐为空的情况。这些解决方案将错误地确定 FFFT 将包含 2 个空格,而不仅仅是一个。因此,我们需要从第三个元素(而不是第二个)开始,并以索引长度 - 3(而不是长度 - 2)结束。此外,在遍历数组时,如果找到符合条件的索引,则该索引只会增加 2,否则 TTFFFFT 将提供 2 个可用图而不是 1 个。除非您在循环时更改数组或使用数组的副本并更改它,否则这是正确的。
编辑:这是正确的,除非问题是有多少空间可用于种植,而不是可以添加多少植物
【讨论】:
以上是关于在安排中编号花盆的主要内容,如果未能解决你的问题,请参考以下文章