The "Immediate Food Delivery II" problem involves analyzing a list of food delivery orders to determine the percentage of customers who received their first order immediately (i.e., with a delivery time of zero minutes). Each order is represented by a set of attributes, typically including customer_id
, order_date
, order_id
, and delivery_time
. The key constraint is to consider only each customer's first order chronologically and check if it was delivered immediately. The output should be the percentage (rounded to two decimal places) of such customers relative to all customers who have placed at least one order.
The problem requires careful handling of:
order_date
or order_id
if dates are the same).delivery_time
equals zero for that order.At first glance, the problem seems to require checking every order, but the focus is solely on each customer's first order. A brute-force approach would be to sort all orders for each customer, find the earliest, and then check if it was delivered immediately. However, this can be optimized.
Instead of scanning all orders repeatedly, we can:
customer_id
.order_date
(and order_id
as a tiebreaker if needed).delivery_time == 0
.Let's break down the solution into clear steps:
customer_id
and the value is a list of that customer's orders.order_date
(and order_id
if needed).delivery_time
is zero, increment a counter for immediate deliveries.We use a hash map for efficient grouping and lookup, and a simple iteration for counting, ensuring the solution is both clear and performant.
Suppose we have the following orders:
customer_id=1
, order_date=2021-01-01
, delivery_time=0
customer_id=1
, order_date=2021-01-02
, delivery_time=5
customer_id=2
, order_date=2021-01-01
, delivery_time=10
customer_id=3
, order_date=2021-01-02
, delivery_time=0
delivery_time=0
)delivery_time=10
)delivery_time=0
)
The output would be 66.67
.
Brute-Force Approach:
n
orders and m
customers, this is O(mn).The optimized approach is much more efficient, especially when the number of customers is much less than the number of orders.
The solution to "Immediate Food Delivery II" centers on efficiently determining, for each customer, whether their first order was delivered immediately. By grouping orders by customer and focusing only on the earliest order for each, we avoid unnecessary computation. Using hash maps and simple counting, we achieve an elegant and performant solution that is easy to implement and understand. The key insight is to focus on the first order per customer and count how many were delivered with zero delay.
from typing import List, Dict
def immediate_food_delivery_percentage(orders: List[Dict]) -> float:
from collections import defaultdict
# Group orders by customer_id
customer_orders = defaultdict(list)
for order in orders:
customer_orders[order['customer_id']].append(order)
immediate = 0
total = len(customer_orders)
for order_list in customer_orders.values():
# Sort orders by order_date, then order_id
order_list.sort(key=lambda x: (x['order_date'], x['order_id']))
first_order = order_list[0]
if first_order['delivery_time'] == 0:
immediate += 1
if total == 0:
return 0.00
return round(immediate * 100 / total, 2)
#include <vector>
#include <unordered_map>
#include <algorithm>
#include <string>
using namespace std;
struct Order {
int customer_id;
string order_date;
int order_id;
int delivery_time;
};
double immediateFoodDeliveryPercentage(const vector<Order>& orders) {
unordered_map<int, vector<Order>> customerOrders;
for (const auto& order : orders) {
customerOrders[order.customer_id].push_back(order);
}
int immediate = 0;
int total = customerOrders.size();
for (auto& kv : customerOrders) {
auto& orderList = kv.second;
sort(orderList.begin(), orderList.end(), [](const Order& a, const Order& b) {
if (a.order_date != b.order_date)
return a.order_date < b.order_date;
return a.order_id < b.order_id;
});
if (orderList[0].delivery_time == 0) {
immediate++;
}
}
if (total == 0) return 0.0;
return round(immediate * 10000.0 / total) / 100.0;
}
import java.util.*;
class Order {
int customer_id;
String order_date;
int order_id;
int delivery_time;
public Order(int customer_id, String order_date, int order_id, int delivery_time) {
this.customer_id = customer_id;
this.order_date = order_date;
this.order_id = order_id;
this.delivery_time = delivery_time;
}
}
public class Solution {
public double immediateFoodDeliveryPercentage(List<Order> orders) {
Map<Integer, List<Order>> customerOrders = new HashMap<>();
for (Order order : orders) {
customerOrders.computeIfAbsent(order.customer_id, k -> new ArrayList<>()).add(order);
}
int immediate = 0;
int total = customerOrders.size();
for (List<Order> orderList : customerOrders.values()) {
orderList.sort((a, b) -> {
int cmp = a.order_date.compareTo(b.order_date);
if (cmp != 0) return cmp;
return Integer.compare(a.order_id, b.order_id);
});
if (orderList.get(0).delivery_time == 0) {
immediate++;
}
}
if (total == 0) return 0.0;
return Math.round(immediate * 10000.0 / total) / 100.0;
}
}
function immediateFoodDeliveryPercentage(orders) {
const customerOrders = new Map();
for (const order of orders) {
if (!customerOrders.has(order.customer_id)) {
customerOrders.set(order.customer_id, []);
}
customerOrders.get(order.customer_id).push(order);
}
let immediate = 0;
const total = customerOrders.size;
for (const orderList of customerOrders.values()) {
orderList.sort((a, b) => {
if (a.order_date !== b.order_date) {
return a.order_date < b.order_date ? -1 : 1;
}
return a.order_id - b.order_id;
});
if (orderList[0].delivery_time === 0) {
immediate++;
}
}
if (total === 0) return 0.00;
return Math.round(immediate * 10000 / total) / 100;
}