Dynamic programming is an algorithm design technique that solves problems by breaking them down into smaller overlapping subproblems and storing the solutions to subproblems to avoid recomputing them. It involves building up a solution using previously found subsolutions and working in a bottom-up fashion to solve larger subproblems from solutions to smaller subproblems. Examples where dynamic programming has been applied include computing Fibonacci numbers, finding the shortest paths in a graph, and solving optimization problems like the knapsack problem.