Java: Interleaving multiple arrays into a single array

后端 未结 5 564
误落风尘
误落风尘 2020-12-19 06:13

I found similar question about interleaving two arraylists into one, but its in PHP. I was asked this question in interview as well but could\'nt solve it, came back to SO t

相关标签:
5条回答
  • 2020-12-19 06:27

    For simplicity, assume that the arrays are the same length, and are int arrays.

    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;
    }
    
    0 讨论(0)
  • 2020-12-19 06:28

    I think this is not doable with your given constraints (O(n) time and O(1) space, i.e. no additional space) for an array or array-based list. (Assuming of course, that we can't simply create a new List object delegating to the original ones.)

    If you have two linked lists, this is doable - if we assume the garbage collector is fast enough, i.e. deleting an element from one list and adding it to another list does not violate the space limitation.

    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();
        }
    }
    

    This method works for any pair of lists, but is only O(n) for linked lists.

    For a custom linked list where we can modify the pointers, we don't have to rely on the garbage collector, we would simply change the nodes. Here for a singly-linked list:

    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;
        }
    }
    

    For a doubly-linked list, we would also have to adapt the prev-pointers.

    Here the wrapping variant mentioned in the first paragraph:

    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.
       };
    }
    

    This is actually O(1) in time, too.

    0 讨论(0)
  • 2020-12-19 06:28

    The lists don't have to be the same size:

    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);
                    }
                }
            };
        }
    }
    

    To test this:

    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));
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-19 06:37

    I believe the mod (%) operations in Matt's answer are incorrect. Under the same assumption (that the arrays are the same length), I'd propose the following solution instead:

    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;
    }
    

    I tested (very briefly), and it appears to work, but of course makes no attempt to handle error conditions such as null arguments or input arrays mismatched in size.

    0 讨论(0)
  • 2020-12-19 06:49

    I've done up a small solution going on the assumption that you are talking about using the ArrayList (see my comment on the question). I may be oversimplifying the problem based on some of the responses here, but here goes anyway.

    The below example takes a and b both of type ArrayList<Integer> and interleaves them by inserting b[0] after a[0], b[1] after a[1] etc. This snippet of course naively assumes that a and b are of the same size as per your Edit v1.0. It also does not create a new ArrayList as per your Edit v2.0.

    //a and b are of type ArrayList<Integer>
    for (int i = a.size(); i > 0; i--)
    {
        a.add(i, b.get(i - 1));
    }
    

    No matter what happens if you are combining the ArrayLists you're going to have twice the size.

    0 讨论(0)
提交回复
热议问题