Sự khác biệt giữa ghi nhớ và lập trình động là gì? Tôi nghĩ lập trình động là một tập hợp con của sự ghi nhớ. Đúng không?
Sự khác biệt giữa ghi nhớ và lập trình động là gì? Tôi nghĩ lập trình động là một tập hợp con của sự ghi nhớ. Đúng không?
Câu trả lời:
Bài viết liên quan về Lập trình.Guide: Lập trình động so với ghi nhớ so với lập bảng
Sự khác biệt giữa ghi nhớ và lập trình động là gì?
Ghi nhớ là một thuật ngữ mô tả một kỹ thuật tối ưu hóa trong đó bạn lưu trữ các kết quả được tính toán trước đó và trả về kết quả được lưu trong bộ nhớ cache khi cần tính toán tương tự một lần nữa.
Lập trình động là một kỹ thuật để giải quyết các vấn đề có tính chất đệ quy, lặp đi lặp lại và được áp dụng khi các tính toán của các bài toán con trùng nhau.
Lập trình động thường được thực hiện bằng cách sử dụng bảng, nhưng cũng có thể được thực hiện bằng cách sử dụng ghi nhớ. Vì vậy, như bạn có thể thấy, không ai là "tập hợp con" của người kia.
Một câu hỏi tiếp theo hợp lý là: sự khác biệt giữa lập bảng (kỹ thuật lập trình động điển hình) và ghi nhớ là gì?
Khi bạn giải quyết vấn đề lập trình động bằng cách sử dụng bảng, bạn sẽ giải quyết vấn đề " từ dưới lên ", tức là bằng cách giải quyết tất cả các vấn đề phụ liên quan trước tiên, thường là bằng cách điền vào bảng n chiều. Dựa trên các kết quả trong bảng, giải pháp cho vấn đề "hàng đầu" / ban đầu được tính toán.
Nếu bạn sử dụng ghi nhớ để giải quyết vấn đề, bạn sẽ làm điều đó bằng cách duy trì bản đồ các vấn đề phụ đã được giải quyết. Bạn thực hiện "từ trên xuống " theo nghĩa là bạn giải quyết vấn đề "trên cùng" trước tiên (thường được lặp lại để giải quyết các vấn đề phụ).
Một slide tốt từ đây (liên kết hiện đã chết, slide vẫn tốt):
- Nếu tất cả các bài toán con phải được giải quyết ít nhất một lần, thuật toán lập trình động từ dưới lên thường vượt trội hơn thuật toán ghi nhớ từ trên xuống theo hệ số không đổi
- Không có chi phí cho đệ quy và ít chi phí cho việc duy trì bảng
- Có một số vấn đề mà mẫu truy cập bảng thông thường trong thuật toán lập trình động có thể được khai thác để giảm thời gian hoặc yêu cầu không gian hơn nữa
- Nếu không giải quyết được một số bài toán con trong không gian của bài toán con, thì giải pháp ghi nhớ có ưu điểm là chỉ giải những bài toán con đó là bắt buộc
Tài nguyên bổ sung:
Lập trình động là một mô hình thuật toán giải quyết một vấn đề phức tạp nhất định bằng cách chia nó thành các bài toán con và lưu trữ kết quả của các bài toán con để tránh tính toán lại kết quả tương tự.
http://www.geekforgeek.org/dynamic-programming-set-1/
Ghi nhớ là một phương pháp dễ dàng để theo dõi các giải pháp đã được giải quyết trước đó (thường được triển khai như một cặp giá trị khóa băm, trái ngược với việc lập bảng thường dựa trên mảng) để chúng không được tính toán lại khi gặp lại. Nó có thể được sử dụng trong cả hai phương pháp từ dưới lên hoặc từ trên xuống.
Xem cuộc thảo luận này về ghi nhớ và lập bảng.
Vì vậy, lập trình động là một phương pháp để giải quyết các lớp vấn đề nhất định bằng cách giải quyết các mối quan hệ / đệ quy lặp lại và lưu trữ các giải pháp được tìm thấy trước đó thông qua việc lập bảng hoặc ghi nhớ. Ghi nhớ là một phương pháp để theo dõi các giải pháp cho các vấn đề đã được giải quyết trước đó và có thể được sử dụng với bất kỳ chức năng nào có các giải pháp xác định duy nhất cho một tập hợp đầu vào nhất định.
Lập trình động thường được gọi là Ghi nhớ!
Ghi nhớ là kỹ thuật từ trên xuống (bắt đầu giải quyết vấn đề đã cho bằng cách phá vỡ nó) và lập trình động là một kỹ thuật từ dưới lên (bắt đầu giải quyết từ vấn đề phụ tầm thường, hướng tới vấn đề đã cho)
DP tìm ra giải pháp bằng cách bắt đầu từ (các) trường hợp cơ sở và tiến lên phía trên. DP giải quyết tất cả các vấn đề phụ, bởi vì nó thực hiện từ dưới lên
Không giống như Ghi nhớ, chỉ giải quyết các vấn đề phụ cần thiết
DP có khả năng biến đổi các giải pháp vũ lực theo thời gian theo hàm mũ thành các thuật toán thời gian đa thức.
DP có thể hiệu quả hơn nhiều vì lặp đi lặp lại
Ngược lại, Ghi nhớ phải trả cho chi phí (thường là đáng kể) do đệ quy.
Để đơn giản hơn, Ghi nhớ sử dụng cách tiếp cận từ trên xuống để giải quyết vấn đề tức là bắt đầu bằng vấn đề cốt lõi (chính) sau đó chia nó thành các vấn đề phụ và giải quyết các vấn đề phụ tương tự. Trong phương pháp này, cùng một vấn đề phụ có thể xảy ra nhiều lần và tiêu tốn nhiều chu kỳ CPU hơn, do đó làm tăng độ phức tạp thời gian. Trong khi đó, trong lập trình động, cùng một vấn đề phụ sẽ không được giải quyết nhiều lần nhưng kết quả trước đó sẽ được sử dụng để tối ưu hóa giải pháp.
(1) Ghi nhớ và DP, về mặt khái niệm , thực sự là điều tương tự. Bởi vì: xem xét định nghĩa của DP: "các bài toán con chồng chéo" "và cấu trúc con tối ưu". Ghi nhớ hoàn toàn sở hữu 2.
(2) Ghi nhớ là DP với nguy cơ tràn ngăn xếp là đệ quy sâu. DP từ dưới lên không có rủi ro này.
(3) Ghi nhớ cần một bảng băm. Vì vậy, không gian bổ sung, và một số thời gian tra cứu.
Vì vậy, để trả lời câu hỏi:
- Về mặt khái niệm , (1) có nghĩa là chúng giống nhau.
Nếu đưa (2) vào tài khoản, nếu bạn thực sự muốn, việc ghi nhớ là một tập hợp con của DP, theo nghĩa là một vấn đề có thể giải quyết được bằng cách ghi nhớ sẽ được DP giải quyết, nhưng vấn đề có thể giải quyết được bởi DP có thể giải quyết được bằng cách ghi nhớ (bởi vì nó có thể chồng tràn).
- Đưa (3) vào tài khoản, họ có những khác biệt nhỏ về hiệu suất.
Từ wikipedia:
Ghi nhớ
Trong điện toán, ghi nhớ là một kỹ thuật tối ưu hóa được sử dụng chủ yếu để tăng tốc các chương trình máy tính bằng cách gọi hàm tránh lặp lại việc tính toán kết quả cho các đầu vào được xử lý trước đó.
Lập trình năng động
Trong toán học và khoa học máy tính, lập trình động là một phương pháp để giải quyết các vấn đề phức tạp bằng cách chia chúng thành các bài toán con đơn giản hơn.
Khi chia một vấn đề thành các bài toán con nhỏ hơn / đơn giản hơn, chúng ta thường gặp cùng một bài toán con hơn một lần - vì vậy chúng tôi sử dụng Ghi nhớ để lưu kết quả của các phép tính trước đó vì vậy chúng tôi không cần lặp lại chúng.
Lập trình động thường gặp các tình huống có ý nghĩa khi sử dụng ghi nhớ nhưng Bạn có thể sử dụng một trong hai kỹ thuật mà không nhất thiết phải sử dụng kỹ thuật kia.
Cả Ghi nhớ và Lập trình động chỉ giải quyết một bài toán con riêng lẻ.
Ghi nhớ sử dụng đệ quy và hoạt động từ trên xuống, trong khi lập trình động di chuyển theo hướng ngược lại giải quyết vấn đề từ dưới lên.
Dưới đây là một sự tương tự thú vị -
Từ trên xuống - Đầu tiên bạn nói tôi sẽ chiếm lấy thế giới. Bạn sẽ làm nó thế nào? Bạn nói tôi sẽ tiếp quản châu Á trước. Bạn sẽ làm nó thế nào? Tôi sẽ tiếp quản Ấn Độ trước. Tôi sẽ trở thành Thủ tướng Delhi, v.v.
Từ dưới lên - Bạn nói tôi sẽ trở thành CM của Delhi. Sau đó sẽ tiếp quản Ấn Độ, rồi tất cả các nước khác ở châu Á và cuối cùng tôi sẽ chiếm lấy thế giới.
Tôi muốn đi với một ví dụ ;
Vấn đề:
Bạn đang leo lên một trường hợp cầu thang. Phải mất n bước để đạt đến đỉnh.
Mỗi lần bạn có thể leo 1 hoặc 2 bước. Trong bao nhiêu cách khác nhau bạn có thể leo lên đỉnh?
Đệ quy với Ghi nhớ
Theo cách này, chúng tôi đang cắt tỉa (loại bỏ vật liệu dư thừa từ cây hoặc cây bụi) cây đệ quy với sự trợ giúp của mảng ghi nhớ và giảm kích thước của cây đệ quy lên đến nn.
public class Solution {
public int climbStairs(int n) {
int memo[] = new int[n + 1];
return climb_Stairs(0, n, memo);
}
public int climb_Stairs(int i, int n, int memo[]) {
if (i > n) {
return 0;
}
if (i == n) {
return 1;
}
if (memo[i] > 0) {
return memo[i];
}
memo[i] = climb_Stairs(i + 1, n, memo) + climb_Stairs(i + 2, n, memo);
return memo[i];
}
}
Lập trình năng động
Như chúng ta có thể thấy vấn đề này có thể được chia thành các bài toán con và nó chứa thuộc tính cấu trúc phụ tối ưu, tức là giải pháp tối ưu của nó có thể được xây dựng hiệu quả từ các giải pháp tối ưu của các bài toán con, chúng ta có thể sử dụng lập trình động để giải quyết vấn đề này.
public class Solution {
public int climbStairs(int n) {
if (n == 1) {
return 1;
}
int[] dp = new int[n + 1];
dp[1] = 1;
dp[2] = 2;
for (int i = 3; i <= n; i++) {
dp[i] = dp[i - 1] + dp[i - 2];
}
return dp[n];
}
}
Ví dụ lấy từ https://leetcode.com/probols/climbing-stairs/
Chỉ cần nghĩ về hai cách,
Trong phần Ghi nhớ, chúng ta đi với (1.) trong đó chúng ta lưu từng lệnh gọi hàm trong bộ đệm và gọi lại từ đó. Nó hơi tốn kém vì nó liên quan đến các cuộc gọi đệ quy.
Trong lập trình động chúng ta đi với (2.) trong đó chúng ta duy trì một bảng, từ dưới lên bằng cách giải các bài toán con bằng cách sử dụng dữ liệu được lưu trong bảng, thường được gọi là bảng dp.
Ghi chú:
Cả hai đều có thể áp dụng cho các vấn đề với các vấn đề phụ chồng chéo.
Ghi nhớ thực hiện tương đối kém với DP do các chi phí liên quan trong các cuộc gọi chức năng đệ quy.
Trong lập trình động ,
Trong ghi nhớ ,