我发现similar有关将两个arraylists交错为一个的问题,但它在PHP中。我也在面试中被问过这个问题,但无法解决,回到SO看看是否已经解决了,但我只能找到这个问题paper
那么指向伪代码或方法定义的指针是什么?
大(O)限制:O(n) - 时间成本和O(1) - 空间成本
示例:
a [] = a1,a2,...,a b [] = b1,b2,...,bn
将arraylist重新排列为a1,b1,a2,b2,...,an,bn
Editv1.0 :Arraylists a []和b []大小相同
Editv2.0 :如果问题扩展到在给定的两个数组中重新排列,但是没有创建新数组会怎样?
答案 0 :(得分:7)
为简单起见,假设数组长度相同,并且是int
数组。
int[] merge(int[] a, int[] b)
{
assert (a.length == b.length);
int[] result = new int[a.length + b.length];
for (int i=0; i<a.length; i++)
{
result[i*2] = a[i];
result[i*2+1] = b[i];
}
return result;
}
答案 1 :(得分:3)
我认为对于基于数组或基于数组的列表的给定约束(O(n)
时间和O(1)
空间,即没有额外空间),这是不可行的。 (当然,假设我们不能简单地创建一个委托给原始List对象的新List对象。)
如果你有两个链表,这是可行的 - 如果我们假设垃圾收集器足够快,即从一个列表中删除一个元素并将其添加到另一个列表不会违反空间限制。
public <X> void interleaveLists(List<X> first, List<X> second)
{
ListIterator<X> firstIt = first.listIterator();
ListIterator<X> secondIt = second.listIterator();
while(secondIt.hasNext()) {
fistIt.next();
firstIt.add(secondIt.next());
secondIt.remove();
}
}
此方法适用于任何列表对,但链接列表只有O(n)。
对于我们可以修改指针的自定义链表,我们不必依赖垃圾收集器,我们只需更改节点。这里有一个单链表:
public void interleaveLinkedLists(Node<X> firstList, Node<X> secondList) {
while(secondList != null) {
Node<X> nextFirst = firstList.next;
Node<X> nextSecond = secondList.next;
firstList.next = secondList;
secondList.next = nextFirst;
firstList = nextFirst;
secondList = nextSecond;
}
}
对于双向链表,我们还必须调整prev-pointers。
这里是第一段中提到的包装变体:
public List<X> interleaveLists(final List<X> first, final List<X> second)
{
if (first.size() != second.size())
throw new IllegalArgumentException();
return new AbstractList<X>() {
public int size() {
return 2 * first.size();
}
public X get(int index) {
return index % 2 == 0 ? first.get(index / 2) : second.get(index / 2);
}
// if necessary, add a similar set() method. add/remove are not sensible here.
};
}
这实际上也是O(1)
。
答案 2 :(得分:2)
我做了一个小小的解决方案,假设你在谈论使用ArrayList
(参见我对这个问题的评论)。我可能会根据这里的一些回答过度简化问题,但无论如何都要进行。
以下示例采用类型为ArrayList<Integer>
的a和b,并通过在[1]之后插入b [0],然后在[1]之后插入b [1]等来对它们进行交错。此片段当然天真地假设a和b的大小与Edit v1.0相同。它也不会根据您的Edit v2.0创建新的ArrayList
。
//a and b are of type ArrayList<Integer>
for (int i = a.size(); i > 0; i--)
{
a.add(i, b.get(i - 1));
}
无论你在组合ArrayLists时会发生什么,你的大小都会达到两倍。
答案 3 :(得分:0)
我相信Matt的答案中的mod(%)操作是不正确的。在相同的假设下(数组的长度相同),我建议改为:
static int[] merge(final int[] a, final int[] b)
{
final int[] result = new int[a.length * 2];
for (int i=0; i < a.length; i++)
{
result[i << 1] = a[i];
result[(i << 1) + 1] = b[i];
}
return result;
}
我测试过(非常简短),它似乎工作,但当然不会尝试处理错误条件,如空参数或输入数组大小不匹配。
答案 4 :(得分:0)
同时引入了 lambda
O(n) 时间复杂度
O(1) 空间复杂度
int[] merge(int[] a, int[] b) {
return( IntStream.range( 0, a.length ).flatMap(
n -> IntStream.of( a[n], b[n] ) ).toArray() );
}
答案 5 :(得分:-1)
列表的大小不必相同:
public class InterleaveTwoLists<X> {
public List<X> interleaveLists(final List<X> first, final List<X> second) {
return new AbstractList<X>() {
private int minSize;
private int combinedMinSize;
private int size;
private List<X>largerList;
{{
minSize = Math.min(first.size(), second.size());
combinedMinSize = minSize*2;
size = first.size() + second.size();
largerList = first.size() > minSize ? first : second;
}}
public int size() {
return size;
}
public X get(int index) {
if (index < combinedMinSize) {
return index % 2 == 0
? first.get(index / 2)
: second.get(index / 2);
}
else {
return largerList.get(index-minSize);
}
}
};
}
}
测试一下:
public class InterleaveTwoListsTest {
private static final Logger log =
LoggerFactory.getLogger(InterleaveTwoListsTest.class);
List<String> first = new ArrayList<String>() {
{
add("one"); add("three"); add("five");
add("seven"); add("eight"); add("nine");
}};
List<String> second = new ArrayList<String>() {
{
add("two"); add("four"); add("six");
}};
private InterleaveTwoLists<String> interleaveTwoLists;
@Before
public void setUp() throws Exception {
interleaveTwoLists = new InterleaveTwoLists<>();
}
@Test
public void test() {
List<String> combinedList = interleaveTwoLists.interleaveLists(first, second);
for( int i = 0; i < first.size() + second.size(); i++) {
log.debug("{}: {}", i, combinedList.get(i));
}
}
}