238 - Product of Array Except Self

本文介绍了一种高效算法,用于求解给定数组中每个元素对应的除自身以外所有元素的乘积,且不使用除法操作。该算法遵循O(n)的时间复杂度要求,并探讨了常数空间复杂度的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Problem

Given an array nums of n integers where n > 1,  return an array output such that output[i] is equal to the product of all the elements of nums except nums[i].

Example:

Input:  [1,2,3,4]
Output: [24,12,8,6]

Note: Please solve it without division and in O(n).

Follow up:
Could you solve it with constant space complexity? (The output array does not count as extra space for the purpose of space complexity analysis.)

Code

class Solution {
public:
    vector<int> productExceptSelf(vector<int>& nums) {
        vector<int> vec; 
        int size = nums.size(); 
        if (size == 0 || size == 1) {
            return vec;
        }
        int t = 1, a[size], c[size];
        for (int i = 0; i < size; ++i) {
            a[i] = t * nums[i];
            t *= nums[i];
        }
        t = 1;
        for (int i = size - 1; i >= 0; --i) {
            c[i] = t * nums[i];
            t = t * nums[i];
        }
        vec.push_back(c[1]);
        for (int i = 1; i < size - 1; ++i) {
            vec.push_back(a[i - 1] * c[i + 1]);
        }
        vec.push_back(a[size - 2]);
        return vec;
    }
};

Link: https://leetcode.com/problems/product-of-array-except-self/

lass RRTStar3D: def __init__(self, start, goal, builds, bounds, max_iter=RRT_MAX_ITER, step_size=RRT_STEP, neighbor_radius=RRT_NEIGHBOR_RADIUS): self.start = np.array(start) self.goal = np.array(goal) # Pre-calculate builds with safety height buffer self.builds_with_safety = builds.copy() self.builds_with_safety[:, 4] -= SAFE_HEIGHT # Decrease zmin self.builds_with_safety[:, 5] += SAFE_HEIGHT # Increase zmax # Ensure zmin is not negative if SAFE_HEIGHT is large self.builds_with_safety[:, 4] = np.maximum(0, self.builds_with_safety[:, 4]) self.bounds = np.array(bounds) # Ensure bounds is numpy array self.max_iter = max_iter self.step_size = step_size self.neighbor_radius = neighbor_radius self.nodes = [self.start] self.parent = {tuple(self.start): None} self.cost = {tuple(self.start): 0.0} # Initialize KDTree with the start node self.kdtree = cKDTree(np.array([self.start])) # Ensure it's a 2D array def sample(self): # Biased sampling towards goal occasionally if np.random.rand() < 0.1: # 10% chance to sample goal return self.goal # Sample within bounds return np.random.uniform(self.bounds[:, 0], self.bounds[:, 1]) def nearest(self, q): _, idx = self.kdtree.query(q) # Handle case where KDTree might have only one node initially if isinstance(idx, (int, np.integer)): return self.nodes[idx] else: # Should not happen if tree has >= 1 node, but safety check return self.nodes[0] def steer(self, q_near, q_rand): delta = q_rand - q_near dist = np.linalg.norm(delta) if dist == 0: # Avoid division by zero return q_near ratio = self.step_size / dist if ratio >= 1.0: return q_rand return q_near + delta * ratio def near_neighbors(self, q_new): # Ensure nodes list is not empty before querying if not self.nodes: return [] # Ensure kdtree has points before querying if self.kdtree.n == 0: return [] # Use query_ball_point which is efficient for radius searches indices = self.kdtree.query_ball_point(q_new, self.neighbor_radius) # Filter out the index of q_new itself if it's already in nodes (might happen during rewiring) q_new_tuple = tuple(q_new) neighbors = [] for i in indices: # Check bounds and ensure it's not the node itself if already added # This check might be redundant if q_new isn't added before calling this if i < len(self.nodes): # Ensure index is valid node = self.nodes[i] if tuple(node) != q_new_tuple: neighbors.append(node) return neighbors def plan(self): for i in range(self.max_iter): q_rand = self.sample() # Check if nodes list is empty (shouldn't happen after init) if not self.nodes: print("Warning: Node list empty during planning.") continue # Or handle appropriately q_near = self.nearest(q_rand) q_new = self.steer(q_near, q_rand) # Check collision for the new segment using the pre-calculated safe builds if check_segment_collision(q_near, q_new, self.builds_with_safety) > 0: continue # If collision-free, add the node and update KD-Tree periodically q_new_tuple = tuple(q_new) q_near_tuple = tuple(q_near) # Choose parent with minimum cost among neighbors min_cost = self.cost[q_near_tuple] + np.linalg.norm(q_new - q_near) best_parent_node = q_near neighbors = self.near_neighbors(q_new) # Find neighbors first for q_neighbor in neighbors: q_neighbor_tuple = tuple(q_neighbor) # Check connectivity collision if check_segment_collision(q_neighbor, q_new, self.builds_with_safety) == 0: new_cost = self.cost[q_neighbor_tuple] + np.linalg.norm(q_new - q_neighbor) if new_cost < min_cost: min_cost = new_cost best_parent_node = q_neighbor # Add the new node with the best parent found self.nodes.append(q_new) q_best_parent_tuple = tuple(best_parent_node) self.parent[q_new_tuple] = q_best_parent_tuple self.cost[q_new_tuple] = min_cost # Rebuild KDTree periodically if len(self.nodes) % KD_REBUILD_EVERY == 0 or i == self.max_iter - 1: # Important: Ensure nodes is a list of arrays before creating KDTree if self.nodes: # Check if nodes is not empty self.kdtree = cKDTree(np.array(self.nodes)) # Rewire neighbors to go through q_new if it provides a shorter path for q_neighbor in neighbors: q_neighbor_tuple = tuple(q_neighbor) # Check if rewiring through q_new is shorter and collision-free cost_via_new = min_cost + np.linalg.norm(q_neighbor - q_new) if cost_via_new < self.cost[q_neighbor_tuple]: if check_segment_collision(q_new, q_neighbor, self.builds_with_safety) == 0: self.parent[q_neighbor_tuple] = q_new_tuple self.cost[q_neighbor_tuple] = cost_via_new # Check if goal is reached if np.linalg.norm(q_new - self.goal) < self.step_size: # Check final segment collision if check_segment_collision(q_new, self.goal, self.builds_with_safety) == 0: goal_tuple = tuple(self.goal) self.nodes.append(self.goal) # Add goal node self.parent[goal_tuple] = q_new_tuple self.cost[goal_tuple] = min_cost + np.linalg.norm(self.goal - q_new) print(f"RRT*: Goal reached at iteration {i+1}") # Rebuild KDTree one last time if goal is reached self.kdtree = cKDTree(np.array(self.nodes)) break # Exit planning loop else: # Loop finished without reaching goal condition print(f"RRT*: Max iterations ({self.max_iter}) reached. Connecting nearest node to goal.") # Find node closest to goal among existing nodes if not self.nodes: print("Error: No nodes generated by RRT*.") return None # Or raise error nodes_arr = np.array(self.nodes) distances_to_goal = np.linalg.norm(nodes_arr - self.goal, axis=1) nearest_node_idx = np.argmin(distances_to_goal) q_final_near = self.nodes[nearest_node_idx] q_final_near_tuple = tuple(q_final_near) goal_tuple = tuple(self.goal) # Try connecting nearest found node to goal if check_segment_collision(q_final_near, self.goal, self.builds_with_safety) == 0: self.nodes.append(self.goal) self.parent[goal_tuple] = q_final_near_tuple self.cost[goal_tuple] = self.cost[q_final_near_tuple] + np.linalg.norm(self.goal - q_final_near) print("RRT*: Connected nearest node to goal.") else: print("RRT*: Could not connect nearest node to goal collision-free. Returning path to nearest node.") # Path will be constructed to q_final_near instead of goal goal_tuple = q_final_near_tuple # Target for path reconstruction # Backtrack path from goal (or nearest reachable node) path = [] # Start backtracking from the actual last node added (goal or nearest) curr_tuple = goal_tuple if curr_tuple not in self.parent and curr_tuple != tuple(self.start): print(f"Warning: Target node {curr_tuple} not found in parent dict. Path reconstruction might fail.") # Fallback to the last added node if goal wasn't reachable/added correctly if self.nodes: curr_tuple = tuple(self.nodes[-1]) else: return None # No path possible while curr_tuple is not None: # Ensure the node corresponding to the tuple exists # This requires searching self.nodes, which is inefficient. # A better approach is to store nodes in the dict or use indices. # For now, let's assume tuple keys match numpy arrays. path.append(np.array(curr_tuple)) curr_tuple = self.parent.get(curr_tuple, None) if not path: print("Error: Path reconstruction failed.") return None if tuple(path[-1]) != tuple(self.start): print("Warning: Path does not end at start node.") return np.array(path[::-1]) # Reverse to get start -> goal order # --------------------- Path Cost Function (Use safe builds) --------------------- def path_cost(path_pts, builds_with_safety, drone_speed=DRONE_SPEED, penalty_k=PENALTY_K): total_time = 0.0 total_penalty = 0.0 num_segments = len(path_pts) - 1 if num_segments < 1: return 0.0 # No cost for a single point path # Vectorized calculations where possible p = path_pts[:-1] # Start points of segments q = path_pts[1:] # End points of segments segments = q - p distances = np.linalg.norm(segments, axis=1) # Avoid division by zero for zero-length segments valid_segments = distances > 1e-6 if not np.any(valid_segments): return 0.0 # Path has no length p = p[valid_segments] q = q[valid_segments] segments = segments[valid_segments] distances = distances[valid_segments] dir_unit = segments / distances[:, np.newaxis] # Interpolate wind at midpoints for better average (optional, could use start/end) midpoints = p + segments / 2.0 # try: # wind_vectors = interp(midpoints) # except ValueError as e: # print(f"Interpolation error: {e}") # print(f"Midpoints shape: {midpoints.shape}") # # Handle error, e.g., return a large cost or use zero wind # wind_vectors = np.zeros_like(midpoints) # Calculate ground speed component along each segment # Ensure wind_vectors and dir_unit have compatible shapes for dot product # np.einsum is efficient for row-wise dot products # wind_along_path = np.einsum('ij,ij->i', wind_vectors, dir_unit) ground_speeds = np.maximum(drone_speed , 1e-3) # Avoid zero/negative speed # Calculate time for each segment segment_times = distances / ground_speeds total_time = np.sum(segment_times) # Calculate collision penalty (iterate segments as check_segment_collision is per-segment) for i in range(len(p)): # Pass pre-calculated builds_with_safety penetration = check_segment_collision(p[i], q[i], builds_with_safety) if penetration > 0: total_penalty += penalty_k * penetration**2 # Quadratic penalty return total_time + total_penalty生成注释
最新发布
05-14
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值