Preface 1 Introduction 1.1 What is an Algorithm? Exercises 1.1 1.2 Fundamentals of Algorithmic Problem Solving Understanding the Problem Ascertaining the Capabilities of a Computational Device Choosing between Exact and Approximate Problem Solving Deciding on Appropriate Data Structures Algorithm Design Techniques Methods of Specifying an Algorithm Proving an Algorithm's Correctness Analyzing an Algorithm Coding an Algorithm Exercises 1.2 1.3 Important Problem Types Sorting Searching String Processing Graph Problems Combinatorial Problems Geometric Problems Numerical Problems Exercises 1.3 1.4 Fundamental Data Structures Linear Data Structures Graphs Trees Sets and Dictionaries Exercises 1.4 Summary 2 Fundamentals of the Analysis of Algorithm Efficiency 2.1 Analysis Framework Measuring an Input's Size Units for Measuring Running -[]me Orders of Growth Worst-Case, Best-Case, and Average-Case Efficlencies Recapitulation of the Analysis Framework Exercises 2.1 2.2 Asymptotic Notations and Basic Efficiency Classes Informal Introduction O-notation 9-notation Onotation Useful Property Involving the Asymptotic Notations Using Limits for Comparing Orders of Growth Basic Efficiency Classes Exercises 2.2 2.3 Mathematical Analysis of Nonrecursive Algorithms Exercises 2.3 2.4 Mathematical Analysis of Recursive Algorithms Exercises 2.4 2.5 Example: Fibonacci Numbers Explicit Formula for the nth Fibonacci Number Algorithms for Computing Fibonacci Numbers Exercises 2.5 3 Brute Force 4 Divide-and-Conquer 5 Decrease-and-Conquer 6 Transform-and-Conquer 7 Space and lime Tradeoffs 8 Dynamic Programming 9 Greedy Technique 10 Iterative Improvement 11 Limitations of Algorithm Power 12 Coping with the Limitations of Algorithm Power Epilogue APPENDIX A Useful Formulas for the Analysis of Algorithms APPENDIX B Short Tutorial on Recurrence Relations Bibliography Hints to Exercises Index