Classic Interview Questions

I came into contact with a classic interview question: a question similar to the optimal solution of the backpack, the original question is as follows
import java.util.List;


public class SplitOrders {
    

    public class Item{
        
        /**
         * seller user id
         */
        long sellerId;
        
        /**
         * Commodity price, unit points
         */
        long price;
    }
    
    public class Order{
        
        /**
         * The product corresponding to the order
         */
        List<Item> orderItems;
        
        /**
         * The order amount, unit points
         */
        long totalPrice;
        
        /**
         * The seller userId corresponding to the order
         */
        long sellerId;
    }
    
    
    /**
     * According to the items in the shopping cart, generate the corresponding transaction order, according to the following rules
     * 1. Each transaction order can have multiple items
     * 2. The products of each transaction order can only be from the same seller
     * 3. The total price of each transaction cannot exceed 1,000 yuan
     * 4. The minimum number of transaction orders generated
     * @param items: all items in the cart
     */
    public List<Order> packageItemsToOrders(List<Item> items){
        
        return null;
    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub

    }

}


In fact, it is a problem of optimal order matching.
My solution is to try to make an order amount tend to be 1000, which is relatively simple and rude.
Specific ideas
1. Group according to different sellers
2. Core principle: By collecting orders, each The total amount of the order tends to 1000.
The seller's product list is sorted by price and divided into a low-priced product list (ascending order) and a high-priced product list (descending order),
3. The highest price product + the lowest price product, if it is greater than 1000, the lowest price product Separate high price as an order, remove the list, put the lowest price item back on the list, repeat the above operation
4. The highest price item + the lowest price item, if it is less than 1000, loop to obtain the low price list, add it to the previous result, and terminate if it is greater than 1000 , if it is less than 1000, it will continue.
Every time you get the item in the list, it will pass the remove method. If the item fails to match the order, it will be put back into the list in its original position.


The specific code is as follows
//Group by seller
public List<Order> separationItems(List<Item> items) {
        Map<Long, List<Item>> map = new HashMap<>();
        /**
         * Grouped by seller,
         */
        for (Item item : items) {
            Long sellId = item.sellerId;
            List<Item> sellerList = map.get(sellId);
            if (sellerList == null || sellerList.size() == 0) {
                sellerList = new ArrayList<>();
            }
            sellerList.add(item);
            map.put (sellId, sellerList);
        }
        List<Order> res = new ArrayList<>();
        /**
         * On a seller-by-seller basis, consolidate orders
         */
        for (Long sellId : map.keySet()) {
            List <Order> orderMergeRes = mergeItems (sellId, map.get (sellId));
            res.addAll(orderMergeRes);
        }
        return res;
    }


    /**
     * Commodity list merge operation
     * Try to ensure that the total amount of each order is infinitely close to 1000, add the highest price item to the lowest price, if it is greater than 1000
     * The task is the highest price commodity intelligence
     * Take the following as an example
     * 12,34,45,67,222,555,777,888,999
     * 1.999+12, if it is greater than 1000, then 999 is an independent order
     * 2. Continue to combine 888+12, if it is less than 1000, then continue to +34, if it is greater than 1000, combine 888 34 as one order
     *
     * @param lessThenT
     * @return
     */
        public List<Order> mergeItems(Long sellId, List<Item> lessThenT) {
             Collections.sort(lessThenT);
            int len = lessThenT.size();
            int flag = len% 2 == 0? len / 2: len / 2 + 1;
            // Save the list of low-priced items sorted from small to large
            List<Item> minList = new ArrayList<>();
            // Save the list of high-priced items from large to small
            List<Item> maxList = new ArrayList<>(lessThenT);
            for (int i = 0; i < flag; i++) {
                minList.add(lessThenT.get(i));
                maxList.remove(0);
            }
            Collections.reverse(maxList);
            List<Order> orderList = new ArrayList<>();
            redo:
            while (maxList.size() > 0) {
                Item max = maxList.remove(0);
                Item min = minList.size()==0?null:minList.remove(0);

                /**
                 * The highest price item cannot be combined with other items into one order
                 * or the current low price has been used up
                 */
                if ((min == null || max.price + min.price > 1000)) {
                    /**
                     * Merge failed, return the item to its original place
                     */
                    if(min != null){
                        minList.add(0, min);
                    }
                    List<Item> tmp = new ArrayList<>();
                    tmp.add(max);
                    Order order = new Order();
                    order.orderItems = tmp;
                    order.totalPrice = max.price;
                    order.sellerId = sellId;
                    orderList.add(order);
                    continue;
                } else {
                    /**
                     * If the current highest price can be merged with the lowest price, then try merging with the next lowest price item
                     */
                    List<Item> tmp = new ArrayList<>();
                    tmp.add(max);
                    tmp.add(min);
                    Long total = max.price + min.price;
                    redoLow:
                    while (minList.size() > 0) {
                        Item minSecond = minList.remove(0);
                        if ((total + minSecond.price) > 1000) {
                            minList.add(0, minSecond);
                            Order order = new Order();
                            order.orderItems = tmp;
                            order.totalPrice = total;
                            order.sellerId = sellId;
                            orderList.add(order);
                            // High-priced items are consumed in advance, split the list of low-priced items and repeat the previous step
                            if (maxList.size() == 0 && minList.size() > 0) {
                                maxList.add(0, minList.remove(minList.size() - 1));
                            }
                            continue redo;
                        } else {
                            tmp.add(minSecond);
                            total = total + minSecond.price;
                        }
                        // Low-priced items are consumed in advance, remove the smallest high-priced items to low prices
                        if (minList.size() == 0 && maxList.size() > 0) {
                            minList.add(0, maxList.remove(maxList.size() - 1));
                            continue redoLow;
                        }
                    }
                    Order order = new Order();
                    order.orderItems = tmp;
                    order.totalPrice = total;
                    order.sellerId = sellId;
                    orderList.add(order);
                }
            }
            return orderList;
        }



Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326751847&siteId=291194637