Chapter: Introduction to the Design and Analysis of Algorithms
Fundamentals of Algorithmic Problem Solving
Let us start by reiterating an important point made in the introduction to this chapter:
We can consider algorithms to be procedural solutions to problems.
These solutions are not answers but specific instructions for getting answers. It is this emphasis on precisely defined constructive procedures that makes computer science distinct from other disciplines. In particular, this distinguishes it from the-oretical mathematics, whose practitioners are typically satisfied with just proving the existence of a solution to a problem and, possibly, investigating the solution’s properties.
We now list and briefly discuss a sequence of steps one typically goes through in designing and analyzing an algorithm (Figure 1.2).
Understanding the Problem
From a practical perspective, the first thing you need to do before designing an algorithm is to understand completely the problem given. Read the problem’s description carefully and ask questions if you have any doubts about the problem, do a few small examples by hand, think about special cases, and ask questions again if needed.
There are a few types of problems that arise in computing applications quite often. We review them in the next section. If the problem in question is one of them, you might be able to use a known algorithm for solving it. Of course, it helps to understand how such an algorithm works and to know its strengths and weaknesses, especially if you have to choose among several available algorithms. But often you will not find a readily available algorithm and will have to design your own. The sequence of steps outlined in this section should help you in this exciting but not always easy task.
An input to an algorithm specifies an instance of the problem the algorithm solves. It is very important to specify exactly the set of instances the algorithm needs to handle. (As an example, recall the variations in the set of instances for the three greatest common divisor algorithms discussed in the previous section.) If you fail to do this, your algorithm may work correctly for a majority of inputs but crash on some “boundary” value. Remember that a correct algorithm is not one that works most of the time, but one that works correctly for all legitimate inputs.
Do not skimp on this first step of the algorithmic problem-solving process; otherwise, you will run the risk of unnecessary rework.
Ascertaining the Capabilities of the Computational Device
Once you completely understand a problem, you need to ascertain the capabilities of the computational device the algorithm is intended for. The vast majority of
algorithms in use today are still destined to be programmed for a computer closely resembling the von Neumann machine—a computer architecture outlined by the prominent Hungarian-American mathematician John von Neumann (1903– 1957), in collaboration with A. Burks and H. Goldstine, in 1946. The essence of this architecture is captured by the so-called random-access machine ( RAM ). Its central assumption is that instructions are executed one after another, one operation at a time. Accordingly, algorithms designed to be executed on such machines are called sequential algorithms .
The central assumption of the RAM model does not hold for some newer computers that can execute operations concurrently, i.e., in parallel. Algorithms that take advantage of this capability are called parallel algorithms . Still, studying the classic techniques for design and analysis of algorithms under the RAM model remains the cornerstone of algorithmics for the foreseeable future.
Should you worry about the speed and amount of memory of a computer at your disposal? If you are designing an algorithm as a scientific exercise, the answer is a qualified no. As you will see in Section 2.1, most computer scientists prefer to study algorithms in terms independent of specification parameters for a particular computer. If you are designing an algorithm as a practical tool, the answer may depend on a problem you need to solve. Even the “slow” computers of today are almost unimaginably fast. Consequently, in many situations you need not worry about a computer being too slow for the task. There are important problems, however, that are very complex by their nature, or have to process huge volumes of data, or deal with applications where the time is critical. In such situations, it is imperative to be aware of the speed and memory available on a particular computer system.
Choosing between Exact and Approximate Problem Solving
The next principal decision is to choose between solving the problem exactly or solving it approximately. In the former case, an algorithm is called an exact algo-rithm ; in the latter case, an algorithm is called an approximation algorithm . Why would one opt for an approximation algorithm? First, there are important prob-lems that simply cannot be solved exactly for most of their instances; examples include extracting square roots, solving nonlinear equations, and evaluating def-inite integrals. Second, available algorithms for solving a problem exactly can be unacceptably slow because of the problem’s intrinsic complexity. This happens, in particular, for many problems involving a very large number of choices; you will see examples of such difficult problems in Chapters 3, 11, and 12. Third, an ap-proximation algorithm can be a part of a more sophisticated algorithm that solves a problem exactly.
Algorithm Design Techniques
Now, with all the components of the algorithmic problem solving in place, how do you design an algorithm to solve a given problem? This is the main question this book seeks to answer by teaching you several general design techniques.
What is an algorithm design technique?
An algorithm design technique (or “strategy” or “paradigm”) is a general approach to solving problems algorithmically that is applicable to a variety of problems from different areas of computing.
Check this book’s table of contents and you will see that a majority of its chapters are devoted to individual design techniques. They distill a few key ideas that have proven to be useful in designing algorithms. Learning these techniques is of utmost importance for the following reasons.
First, they provide guidance for designing algorithms for new problems, i.e., problems for which there is no known satisfactory algorithm. Therefore—to use the language of a famous proverb—learning such techniques is akin to learning to fish as opposed to being given a fish caught by somebody else. It is not true, of course, that each of these general techniques will be necessarily applicable to every problem you may encounter. But taken together, they do constitute a powerful collection of tools that you will find quite handy in your studies and work.
Second, algorithms are the cornerstone of computer science. Every science is interested in classifying its principal subject, and computer science is no exception. Algorithm design techniques make it possible to classify algorithms according to an underlying design idea; therefore, they can serve as a natural way to both categorize and study algorithms.
Designing an Algorithm and Data Structures
While the algorithm design techniques do provide a powerful set of general ap-proaches to algorithmic problem solving, designing an algorithm for a particular problem may still be a challenging task. Some design techniques can be simply inapplicable to the problem in question. Sometimes, several techniques need to be combined, and there are algorithms that are hard to pinpoint as applications of the known design techniques. Even when a particular design technique is ap-plicable, getting an algorithm often requires a nontrivial ingenuity on the part of the algorithm designer. With practice, both tasks—choosing among the general techniques and applying them—get easier, but they are rarely easy.
Of course, one should pay close attention to choosing data structures appro-priate for the operations performed by the algorithm. For example, the sieve of Eratosthenes introduced in Section 1.1 would run longer if we used a linked list instead of an array in its implementation (why?). Also note that some of the al-gorithm design techniques discussed in Chapters 6 and 7 depend intimately on structuring or restructuring data specifying a problem’s instance. Many years ago, an influential textbook proclaimed the fundamental importance of both algo-rithms and data structures for computer programming by its very title: Algorithms + Data Structures = Programs [Wir76]. In the new world of object-oriented programming, data structures remain crucially important for both design and analysis of algorithms. We review basic data structures in Section 1.4.
Methods of Specifying an Algorithm
Once you have designed an algorithm, you need to specify it in some fashion. In Section 1.1, to give you an example, Euclid’s algorithm is described in words (in a free and also a step-by-step form) and in pseudocode. These are the two options that are most widely used nowadays for specifying algorithms.
Using a natural language has an obvious appeal; however, the inherent ambi-guity of any natural language makes a succinct and clear description of algorithms surprisingly difficult. Nevertheless, being able to do this is an important skill that you should strive to develop in the process of learning algorithms.
Pseudocode is a mixture of a natural language and programming language-like constructs. Pseudocode is usually more precise than natural language, and its usage often yields more succinct algorithm descriptions. Surprisingly, computer scientists have never agreed on a single form of pseudocode, leaving textbook authors with a need to design their own “dialects.” Fortunately, these dialects are so close to each other that anyone familiar with a modern programming language should be able to understand them all.
This book’s dialect was selected to cause minimal difficulty for a reader. For the sake of simplicity, we omit declarations of variables and use indentation to show the scope of such statements as for , if , and while . As you saw in the previous section, we use an arrow “ ← ” for the assignment operation and two slashes “ // ” for comments.
In the earlier days of computing, the dominant vehicle for specifying algo-rithms was a flowchart , a method of expressing an algorithm by a collection of connected geometric shapes containing descriptions of the algorithm’s steps. This representation technique has proved to be inconvenient for all but very simple algorithms; nowadays, it can be found only in old algorithm books.
The state of the art of computing has not yet reached a point where an algorithm’s description—be it in a natural language or pseudocode—can be fed into an electronic computer directly. Instead, it needs to be converted into a computer program written in a particular computer language. We can look at such a program as yet another way of specifying the algorithm, although it is preferable to consider it as the algorithm’s implementation.
Proving an Algorithm’s Correctness
Once an algorithm has been specified, you have to prove its correctness . That is, you have to prove that the algorithm yields a required result for every legitimate input in a finite amount of time. For example, the correctness of Euclid’s algorithm for computing the greatest common divisor stems from the correctness of the equality gcd (m, n) = gcd (n, m mod n) (which, in turn, needs a proof; see Problem 7 in Exercises 1.1), the simple observation that the second integer gets smaller on every iteration of the algorithm, and the fact that the algorithm stops when the second integer becomes 0.
For some algorithms, a proof of correctness is quite easy; for others, it can be quite complex. A common technique for proving correctness is to use mathemati-cal induction because an algorithm’s iterations provide a natural sequence of steps needed for such proofs. It might be worth mentioning that although tracing the algorithm’s performance for a few specific inputs can be a very worthwhile activ-ity, it cannot prove the algorithm’s correctness conclusively. But in order to show that an algorithm is incorrect, you need just one instance of its input for which the algorithm fails.
The notion of correctness for approximation algorithms is less straightforward than it is for exact algorithms. For an approximation algorithm, we usually would like to be able to show that the error produced by the algorithm does not exceed a predefined limit. You can find examples of such investigations in Chapter 12.
Analyzing an Algorithm
We usually want our algorithms to possess several qualities. After correctness, by far the most important is efficiency . In fact, there are two kinds of algorithm efficiency: time efficiency , indicating how fast the algorithm runs, and space ef-ficiency , indicating how much extra memory it uses. A general framework and specific techniques for analyzing an algorithm’s efficiency appear in Chapter 2.
Another desirable characteristic of an algorithm is simplicity . Unlike effi-ciency, which can be precisely defined and investigated with mathematical rigor, simplicity, like beauty, is to a considerable degree in the eye of the beholder. For example, most people would agree that Euclid’s algorithm is simpler than the middle-school procedure for computing gcd (m, n) , but it is not clear whether Eu-clid’s algorithm is simpler than the consecutive integer checking algorithm. Still, simplicity is an important algorithm characteristic to strive for. Why? Because sim-pler algorithms are easier to understand and easier to program; consequently, the resulting programs usually contain fewer bugs. There is also the undeniable aes-thetic appeal of simplicity. Sometimes simpler algorithms are also more efficient than more complicated alternatives. Unfortunately, it is not always true, in which case a judicious compromise needs to be made.
Yet another desirable characteristic of an algorithm is generality . There are, in fact, two issues here: generality of the problem the algorithm solves and the set of inputs it accepts. On the first issue, note that it is sometimes easier to design an algorithm for a problem posed in more general terms. Consider, for example, the problem of determining whether two integers are relatively prime, i.e., whether their only common divisor is equal to 1. It is easier to design an algorithm for a more general problem of computing the greatest common divisor of two integers and, to solve the former problem, check whether the gcd is 1 or not. There are situations, however, where designing a more general algorithm is unnecessary or difficult or even impossible. For example, it is unnecessary to sort a list of n numbers to find its median, which is its n/ 2 th smallest element. To give another example, the standard formula for roots of a quadratic equation cannot be generalized to handle polynomials of arbitrary degrees.
As to the set of inputs, your main concern should be designing an algorithm that can handle a set of inputs that is natural for the problem at hand. For example, excluding integers equal to 1 as possible inputs for a greatest common divisor algorithm would be quite unnatural. On the other hand, although the standard formula for the roots of a quadratic equation holds for complex coefficients, we would normally not implement it on this level of generality unless this capability is explicitly required.
If you are not satisfied with the algorithm’s efficiency, simplicity, or generality, you must return to the drawing board and redesign the algorithm. In fact, even if your evaluation is positive, it is still worth searching for other algorithmic solutions. Recall the three different algorithms in the previous section for computing the greatest common divisor: generally, you should not expect to get the best algorithm on the first try. At the very least, you should try to fine-tune the algorithm you already have. For example, we made several improvements in our implementation of the sieve of Eratosthenes compared with its initial outline in Section 1.1. (Can you identify them?) You will do well if you keep in mind the following observation of Antoine de Saint-Exupery,´ the French writer, pilot, and aircraft designer: “A designer knows he has arrived at perfection not when there is no longer anything to add, but when there is no longer anything to take away.” 1
Coding an Algorithm
Most algorithms are destined to be ultimately implemented as computer pro-grams. Programming an algorithm presents both a peril and an opportunity. The peril lies in the possibility of making the transition from an algorithm to a pro-gram either incorrectly or very inefficiently. Some influential computer scientists strongly believe that unless the correctness of a computer program is proven with full mathematical rigor, the program cannot be considered correct. They have developed special techniques for doing such proofs (see [Gri81]), but the power of these techniques of formal verification is limited so far to very small programs.
As a practical matter, the validity of programs is still established by testing. Testing of computer programs is an art rather than a science, but that does not mean that there is nothing in it to learn. Look up books devoted to testing and debugging; even more important, test and debug your program thoroughly whenever you implement an algorithm.
Also note that throughout the book, we assume that inputs to algorithms belong to the specified sets and hence require no verification. When implementing algorithms as programs to be used in actual applications, you should provide such verifications.
Of course, implementing an algorithm correctly is necessary but not sufficient: you would not like to diminish your algorithm’s power by an inefficient implemen-tation. Modern compilers do provide a certain safety net in this regard, especially when they are used in their code optimization mode. Still, you need to be aware of such standard tricks as computing a loop’s invariant (an expression that does not change its value) outside the loop, collecting common subexpressions, replac-ing expensive operations by cheap ones, and so on. (See [Ker99] and [Ben00] for a good discussion of code tuning and other issues related to algorithm program-ming.) Typically, such improvements can speed up a program only by a constant factor, whereas a better algorithm can make a difference in running time by orders of magnitude. But once an algorithm is selected, a 10–50% speedup may be worth an effort.
A working program provides an additional opportunity in allowing an em-pirical analysis of the underlying algorithm. Such an analysis is based on timing the program on several inputs and then analyzing the results obtained. We dis-cuss the advantages and disadvantages of this approach to analyzing algorithms in Section 2.6.
In conclusion, let us emphasize again the main lesson of the process depicted in Figure 1.2:
As a rule, a good algorithm is a result of repeated effort and rework.
Even if you have been fortunate enough to get an algorithmic idea that seems perfect, you should still try to see whether it can be improved.
Actually, this is good news since it makes the ultimate result so much more enjoyable. (Yes, I did think of naming this book The Joy of Algorithms .) On the other hand, how does one know when to stop? In the real world, more often than not a project’s schedule or the impatience of your boss will stop you. And so it should be: perfection is expensive and in fact not always called for. Designing an algorithm is an engineering-like activity that calls for compromises among competing goals under the constraints of available resources, with the designer’s time being one of the resources.
In the academic world, the question leads to an interesting but usually difficult investigation of an algorithm’s optimality . Actually, this question is not about the efficiency of an algorithm but about the complexity of the problem it solves: What is the minimum amount of effort any algorithm will need to exert to solve the problem? For some problems, the answer to this question is known. For example, any algorithm that sorts an array by comparing values of its elements needs about n log 2 n comparisons for some arrays of size n (see Section 11.2). But for many seemingly easy problems such as integer multiplication, computer scientists do not yet have a final answer.
Another important issue of algorithmic problem solving is the question of whether or not every problem can be solved by an algorithm. We are not talking here about problems that do not have a solution, such as finding real roots of a quadratic equation with a negative discriminant. For such cases, an output indicating that the problem does not have a solution is all we can and should expect from an algorithm. Nor are we talking about ambiguously stated problems. Even some unambiguous problems that must have a simple yes or no answer are “undecidable,” i.e., unsolvable by any algorithm. An important example of such a problem appears in Section 11.3. Fortunately, a vast majority of problems in practical computing can be solved by an algorithm.
Before leaving this section, let us be sure that you do not have the misconception—possibly caused by the somewhat mechanical nature of the diagram of Figure 1.2—that designing an algorithm is a dull activity. There is nothing further from the truth: inventing (or discovering?) algorithms is a very creative and rewarding process. This book is designed to convince you that this is the case.
Exercises 1.2
Old World puzzle A peasant finds himself on a riverbank with a wolf, a goat, and a head of cabbage. He needs to transport all three to the other side of the river in his boat. However, the boat has room for only the peasant himself and one other item (either the wolf, the goat, or the cabbage). In his absence, the wolf would eat the goat, and the goat would eat the cabbage. Solve this problem for the peasant or prove it has no solution. (Note: The peasant is a vegetarian but does not like cabbage and hence can eat neither the goat nor the cabbage to help him solve the problem. And it goes without saying that the wolf is a protected species.)
New World puzzle There are four people who want to cross a rickety bridge; they all begin on the same side. You have 17 minutes to get them all across to the other side. It is night, and they have one flashlight. A maximum of two people can cross the bridge at one time. Any party that crosses, either one or two people, must have the flashlight with them. The flashlight must be walked back and forth; it cannot be thrown, for example. Person 1 takes 1 minute to cross the bridge, person 2 takes 2 minutes, person 3 takes 5 minutes, and person 4 takes 10 minutes. A pair must walk together at the rate of the slower person’s pace. (Note: According to a rumor on the Internet, interviewers at a well-known software company located near Seattle have given this problem to interviewees.)
Which of the following formulas can be considered an algorithm for comput-ing the area of a triangle whose side lengths are given positive numbers a , b , and c ?
Write pseudocode for an algorithm for finding real roots of equation ax 2 + bx + c = 0 for arbitrary real coefficients a, b, and c. (You may assume the availability of the square root function sqrt (x). )
Describe the standard algorithm for finding the binary representation of a positive decimal integer
in English.
in pseudocode.
Describe the algorithm used by your favorite ATM machine in dispensing cash. (You may give your description in either English or pseudocode, which-ever you find more convenient.)
a. Can the problem of computing the number π be solved exactly?
How many instances does this problem have?
Look up an algorithm for this problem on the Internet.
Give an example of a problem other than computing the greatest common divisor for which you know more than one algorithm. Which of them is simpler? Which is more efficient?
Consider the following algorithm for finding the distance between the two closest elements in an array of numbers.
ALGORITHM MinDistance (A [0 ..n − 1] )
//Input: Array A [0 ..n − 1] of numbers
//Output: Minimum distance between two of its elements dmin ← ∞
for i ← 0 to n − 1 do
for j ← 0 to n − 1 do
if i = j and |A[i] − A[j ]| < dmin dmin ← |A[i] − A[j ]|
return dmin
Make as many improvements as you can in this algorithmic solution to the problem. If you need to, you may change the algorithm altogether; if not, improve the implementation given.
One of the most influential books on problem solving, titled How To Solve It [Pol57], was written by the Hungarian-American mathematician George Polya´ (1887–1985). Polya´ summarized his ideas in a four-point summary. Find this summary on the Internet or, better yet, in his book, and compare it with the plan outlined in Section 1.2. What do they have in common? How are they different?
Related Topics
Privacy Policy , Terms and Conditions , DMCA Policy and Compliant
Copyright © 2018-2023 BrainKart.com; All Rights Reserved. Developed by Therithal info, Chennai.
How to Solve an Algorithm Problem? | With Examples
If you’re stuck on an algorithm problem and not sure how to proceed, this blog post is for you! We’ll go over some general tips on solving algorithm problems, as well as a specific example of an algorithm .
Table of content:
Introduction.
- What are the 4 steps of algorithmic problem solving?
- Conclusion and References
What is an Algorithm?
What is an algorithm? Put simply, an algorithm is a step-by-step procedure for solving a problem. Algorithms can be written in any programming language, but they all share some common characteristics. First and foremost, algorithms are sequence tasks . That means that the steps in the algorithm must be done in order, and each step depends on the results of the previous steps. Secondly, algorithms are deterministic: given the same input data, exactly the same program will produce the same output every time. Finally, there are some measures for an algorithm to be efficient. Time and space: those two measures determine how efficient your algorithm is.
How to Solve an Algorithm Problem?
We’ll walk through some steps for solving a particular algorithm .
First, it’s important to know the basics of algorithms: every problem can be broken down into a sequence of steps that can be solved. This is known as the analysis of algorithms . Sketch out the basic structure of your algorithm on paper first or a board to avoid confusion. write some thoughts about which does what.
If a problem involves mathematical operations, conceptualizing it in terms of equations may be helpful. Break down the equation into its component parts and see if any of those particular pieces can be simplified or eliminated altogether. If so, that will lead to a solution for the whole equation.
Another strategy is to try reversing what initially seems like an impossible task. Algorithms problems often have stages were doing something one-way results in an error message or produces no useful output at all. Reverse engineer those steps and see if anything productive comes out.
What are the 4 steps of algorithmic problem-solving? and Example #1
Now that you know what an algorithm is, let’s jump into some examples and take a look at how these techniques can be put into practice…
In the following we will use the problem challenge from leetcode number #387 :
1) Understand the problem
The goal of any algorithm is to solve a problem. When solving an algorithm problem, it is important to understand the problem and the steps involved in solving it. This understanding will allow you to correctly follow the instructions and complete the task. Answer the common questions to be sure that you really understand the problem. Questions like what it does and what kind of input I’m expecting. what kind of output I should receive? Are there some exceptions I should be aware of? etc…
The goal of this challenge is to write a function that takes in a string and returns the index of the first letter in the string that does not repeat. For example, if the string is “nerd”, the function should return 0, because the first letter “n” is the first non-repeating letter in the string. If the string is “abcdefg”, the function should return 0, because the first letter “a” is the first non-repeating letter in the string.
If the string does not contain any non-repeating letters, the function should return -1. For example, if the input string is “abcabc”, the function should return -1, because no letter in the string is unique or non-repeating.
2) Break the problem down
When solving algorithms problems , breaking them down into smaller parts is usually the best way to go. Once you understand how each part works and interacts with the others, you can solve the problem more quickly.
To solve this challenge, we need to do the following:
- Iterate over the letters in the input string, and for each letter, keep track of how many times it appears in the string. We can do this using an object, dictionary, or map, where the keys are the letters in the string, and the values are the counts for each letter.
- Once we have counted the occurrences of each letter in the string, we need to find the index of the first letter that has a count of 1 (i.e. the first non-repeating letter). To do this, we can iterate over the letters in the string again, and for each letter, check if its count in the object/dictionary is 1. If it is, we return the index of the letter.
- If we reach the end of the loop without finding any value that has only 1 or non-repeating letters, we return -1 to indicate that no non-repeating letters were found.
3) Find your solution
We found one solution and the key steps in this solution are to keep track of the counts of each letter in the input string, and then to search for the first letter with a count of 1. If the count of this letter is 1 meaning that this letter only shows one time in the string. These steps can be implemented in a variety of ways, depending on the language and tools you are using to solve the challenge.
We will be demonstrating the solution with two programming languages JavaScript and Python:
The source code in JavaScript:
Here are some examples of how this function can be used:
The source code in Python :
4) Check your solution
Checking your solution again answers some questions like can I write a better code? by better I mean is the code I provided covering all cases of inputs? is it efficient? and by efficient, I mean using fewer computer resources when possible. If you’re comfortable with your answers then check if there is another solution out there for the same problem you solved, if any are found. go through them I learned a lot by doing that. Also get some feedback on your code, that way you’ll learn many ways of approaching a problem to solve it.
As we mentioned above we asked ourselves these questions but the algorithm we wrote couldn’t go through all the different cases successfully: for example, The code can’t handle the case when we handled two cases of the same character “L” and “l” in the word “Level”
So we need to address that in the following:
Now let’s revisit the code that we wrote up and see if we can come up with another solution that will cover the all different cases of a character.
The source code in JavaScript :
Now that you learned from the first example, let’s jump into another challenge and apply the same techniques we used above:
This example from leetcode problem #125 Valid Palindrome
Learn as much information as you can about the problem what is a Palindrome? Ask yourself what input you expect and what output is expected.
The Palindrome is a word, phrase, or sentence that is spelled backward as forwards. We expect a string and we can do a function that first cleans that string from any non-alphanumeric, then reverses it and compares it with the original string.
Here is a step-by-step explanation of the algorithm in plain English:
- Convert all uppercase letters in the string to lowercase. This is done so that the case of the letters in the string does not affect the outcome of the comparison.
- Remove all non-alphanumeric characters from the string. This is done because only alphanumeric characters are relevant for determining if a string is a palindrome.
- Reverse the resulting string. This is done so that we can compare the reversed string with the original string.
- Compare the reversed string with the original string. If they are the same, then the original string is a palindrome. Otherwise, it is not.
Here is an example of how this algorithm would work on the string “A man, a plan, a canal: Panama”:
- The string is converted to lowercase, so it becomes “a man, a plan, a canal: panama”.
- All non-alphanumeric characters are removed, so the string becomes “amanaplanacanalpanama”.
- The string is reversed, so it becomes “amanaplanacanalpanama”.
- The reversed string is compared with the original string, and since they are the same, the function returns true, indicating that the original string is a palindrome.
According to the steps we wrote in the previous stage, let’s put them into action and code it up.
The source code in Python:
We can make it more efficient by using the pointers method let’s break it down into a few points below:
- Create left and right pointers (will be represented by indices)
- Make each pointer move to the middle direction
- While moving to check each letter for both pointers are the same
Conclusion and references
There are many resources available to help you out, and with more practice , you’ll be able to solve many algorithm problems that come your way . This video is one of the great resources to learn about algorithms and data structures from FreeCodeCamp
It is important to keep a cool head and not get bogged down in frustration. Algorithms problems can be difficult, but with patience and perseverance, they can be solved.
When you are solving an algorithm problem, it is important to be able to check your solution against other solutions if possible to see how others approach the same problem. This is will help you to retain and understand the logic behind the different solutions so you’ll need this kind of knowledge in the future solving problems.
By following the steps outlined in this article, you will be able to solve algorithm problems with ease. Remember to keep a notebook or excel sheet with all of your solutions so that you can revisit them later on that way you will gain maximum retention of the logic.
If you want to learn more about algorithms and programming , sign up for our mailing list. We’ll send you tips, tricks, and resources to help you improve your skills.
Ahmed Radwan
Reach out if you want to join me and write articles with the nerds 🙂
How to Make Your Corporate Website Stand Out With These 10 Tips
How to write clean code and best practices, you may also like, javascript: resolved and rejected promises, here are some new features in javascript, top 100 problems on leetcode and its solutions – part1.
- Smart Devices
- Programming
- Web Development
- Presentation
- Infographics
- Analysis of Algorithms
- Backtracking
- Dynamic Programming
- Divide and Conquer
- Geometric Algorithms
- Mathematical Algorithms
- Pattern Searching
- Bitwise Algorithms
- Branch & Bound
- Randomized Algorithms
Algorithms Tutorial
Algorithm is a step-by-step procedure for solving a problem or accomplishing a task. In the context of data structures and algorithms, it is a set of well-defined instructions for performing a specific computational task. Algorithms are fundamental to computer science and play a very important role in designing efficient solutions for various problems. Understanding algorithms is essential for anyone interested in mastering data structures and algorithms.
Table of Content
What is an Algorithm?
How do algorithms work.
- What Makes a Good Algorithm?
What is the Need for Algorithms?
Examples of algorithms, how to write an algorithm, learn basics of algorithms, types of algorithms.
An algorithm is a finite sequence of well-defined instructions that can be used to solve a computational problem. It provides a step-by-step procedure that convert an input into a desired output.
Algorithms typically follow a logical structure:
- Input: The algorithm receives input data.
- Processing: The algorithm performs a series of operations on the input data.
- Output: The algorithm produces the desired output.
Characteristics of an Algorithm:
- Clear and Unambiguous: The algorithm should be unambiguous. Each of its steps should be clear in all aspects and must lead to only one meaning.
- Well-defined Inputs: If an algorithm says to take inputs, it should be well-defined inputs. It may or may not take input.
- Well-defined Outputs: The algorithm must clearly define what output will be yielded and it should be well-defined as well. It should produce at least 1 output.
- Finiteness: The algorithm must be finite, i.e. it should terminate after a finite time.
- Feasible: The algorithm must be simple, generic, and practical, such that it can be executed using reasonable constraints and resources.
- Language Independent: Algorithm must be language-independent, i.e. it must be just plain instructions that can be implemented in any language, and yet the output will be the same, as expected.
Algorithms are essential for solving complex computational problems efficiently and effectively. They provide a systematic approach to:
- Solving problems: Algorithms break down problems into smaller, manageable steps.
- Optimizing solutions: Algorithms find the best or near-optimal solutions to problems.
- Automating tasks: Algorithms can automate repetitive or complex tasks, saving time and effort.
Below are some example of algorithms:
- Sorting algorithms: Merge sort, Quick sort, Heap sort
- Searching algorithms: Linear search, Binary search, Hashing
- Graph algorithms: Dijkstra's algorithm, Prim's algorithm, Floyd-Warshall algorithm
- String matching algorithms: Knuth-Morris-Pratt algorithm, Boyer-Moore algorithm
To write an algorithm, follow these steps:
- Define the problem: Clearly state the problem to be solved.
- Design the algorithm: Choose an appropriate algorithm design paradigm and develop a step-by-step procedure.
- Implement the algorithm: Translate the algorithm into a programming language.
- Test and debug: Execute the algorithm with various inputs to ensure its correctness and efficiency.
- Analyze the algorithm: Determine its time and space complexity and compare it to alternative algorithms.
- What is Algorithm | Introduction to Algorithms
- Definition, Types, Complexity, Examples of Algorithms
- Algorithms Design Techniques
- Why is analysis of an Algorithm important?
- Asymptotic Analysis
- Worst, Average and Best Cases
- Asymptotic Notations
- Lower and Upper Bound Theory
- Introduction to Amortized Analysis
- What does ‘Space Complexity’ mean?
- Polynomial Time Approximation Scheme
- Accounting Method | Amortized Analysis
- Potential Method in Amortized Analysis
Algorithms can be different types, depending on what they do and how they're made. Some common types are:
1. Searching and Sorting Algorithms
- Introduction to Searching Algorithms
- Introduction to Sorting Algorithm
- Stable and Unstable Sorting Algorithms
- Lower bound for comparison based sorting algorithms
- Can Run Time Complexity of a comparison-based sorting algorithm be less than N logN?
- Which sorting algorithm makes minimum number of memory writes?
2. Greedy Algorithms
- Introduction to Greedy Algorithms
- Activity Selection Problem
- Huffman Coding
- Job Sequencing Problem
- Quiz on Greedy Algorithms
- Minimum Number of Platforms Required for a Railway/Bus Station
3. Dynamic Programming Algorithms
- Introduction to Dynamic Programming
- Overlapping Subproblems Property
- Optimal Substructure Property
- Longest Increasing Subsequence
- Longest Common Subsequence
- Min Cost Path
- Coin Change
- Matrix Chain Multiplication
- 0-1 Knapsack Problem
- Longest Palindromic Subsequence
- Palindrome Partitioning
4. Pattern Searching Algorithms
- Introduction to Pattern Searching
- Naive Pattern Searching
- KMP Algorithm
- Rabin-Karp Algorithm
- Pattern Searching using a Trie of all Suffixes
- Aho-Corasick Algorithm for Pattern Searching
- Z algorithm (Linear time pattern searching Algorithm)
5. Backtracking Algorithm
- Introduction to Backtracking
- Print all permutations of a given string
- The Knight’s tour problem
- Rat in a Maze
- N Queen Problem
- m Coloring Problem
- Hamiltonian Cycle
6. Divide and Conquer Algorithm
- Introduction to Divide and Conquer
- Write your own pow(x, n) to calculate x*n
- Count Inversions
- Closest Pair of Points
- Strassen’s Matrix Multiplication
7. Geometric Algorithm
- Introduction to Geometric Algorithms
- Closest Pair of Points | O(nlogn) Implementation
- How to check if a given point lies inside or outside a polygon?
- How to check if two given line segments intersect?
- Given n line segments, find if any two segments intersect
- How to check if given four points form a square
- Convex Hull using Jarvis’ Algorithm or Wrapping
8. Mathematical Algorithms
- Introduction to Mathematical Algorithms
- Write an Efficient Method to Check if a Number is Multiple of 3
- Write a program to add two numbers in base 14
- Program for Fibonacci numbers
- Average of a stream of numbers
- Multiply two integers without using multiplication, division and bitwise operators, and no loops
- Babylonian method for square root
- Sieve of Eratosthenes
- Pascal’s Triangle
- Given a number, find the next smallest palindrome
- Program to add two polynomials
- Multiply two polynomials
- Count trailing zeroes in factorial of a number
9. Bitwise Algorithms
- Introduction to Bitwise Algorithms
- Little and Big Endian
- Detect opposite signs
- Turn off the rightmost set bit
- Rotate bits
- Next higher number with same number of set bits
- Swap two nibbles in a byte
10. Graph Algorithms
- Introduction to Graph Algorithms
- Cycles in Graph
- Shortest paths
- Topological Sorting
- Connectivity
11. Randomized Algorithms
- Introduction to Randomized Algorithms
- Linearity of Expectation
- Expected Number of Trials until Success
- Randomized Algorithms | Set 0 (Mathematical Background)
- Randomized Algorithms | Set 1 (Introduction and Analysis)
- Randomized Algorithms | Set 2 (Classification and Applications)
- Randomized Algorithms | Set 3 (1/2 Approximate Median)
- Reservoir Sampling
12. Branch and Bound Algorithms
- Branch and Bound | Set 1 (Introduction with 0/1 Knapsack)
- Branch and Bound | Set 2 (Implementation of 0/1 Knapsack)
- Branch and Bound | Set 3 (8 puzzle Problem)
- Branch And Bound | Set 4 (Job Assignment Problem)
- Branch and Bound | Set 5 (N Queen Problem)
- Branch And Bound | Set 6 (Traveling Salesman Problem)
- Greedy Algorithms
- NP Complete
- Bit Algorithms
Similar Reads
Improve your coding skills with practice.
What kind of Experience do you want to share?
MIT Sloan is the leader in research and teaching in AI. Dive in to discover why.
Which program is right for you?
Through intellectual rigor and experiential learning, this full-time, two-year MBA program develops leaders who make a difference in the world.
Earn your MBA and SM in engineering with this transformative two-year program.
A rigorous, hands-on program that prepares adaptive problem solvers for premier finance careers.
A 12-month program focused on applying the tools of modern data science, optimization and machine learning to solve real-world business problems.
Combine an international MBA with a deep dive into management science. A special opportunity for partner and affiliate schools only.
A doctoral program that produces outstanding scholars who are leading in their fields of research.
Bring a business perspective to your technical and quantitative expertise with a bachelor’s degree in management, business analytics, or finance.
Apply now and work for two to five years. We'll save you a seat in our MBA class when you're ready to come back to campus for your degree.
Executive Programs
The 20-month program teaches the science of management to mid-career leaders who want to move from success to significance.
A full-time MBA program for mid-career leaders eager to dedicate one year of discovery for a lifetime of impact.
A joint program for mid-career professionals that integrates engineering and systems thinking. Earn your master’s degree in engineering and management.
Non-degree programs for senior executives and high-potential managers.
A non-degree, customizable program for mid-career professionals.
To help improve the accuracy of generative AI, add speed bumps
4 capabilities of a real-time business
Slack CEO: How to roll out artificial intelligence internally
Credit: Alejandro Giraldo
Ideas Made to Matter
How to use algorithms to solve everyday problems
Kara Baskin
May 8, 2017
How can I navigate the grocery store quickly? Why doesn’t anyone like my Facebook status? How can I alphabetize my bookshelves in a hurry? Apple data visualizer and MIT System Design and Management graduate Ali Almossawi solves these common dilemmas and more in his new book, “ Bad Choices: How Algorithms Can Help You Think Smarter and Live Happier ,” a quirky, illustrated guide to algorithmic thinking.
For the uninitiated: What is an algorithm? And how can algorithms help us to think smarter?
An algorithm is a process with unambiguous steps that has a beginning and an end, and does something useful.
Algorithmic thinking is taking a step back and asking, “If it’s the case that algorithms are so useful in computing to achieve predictability, might they also be useful in everyday life, when it comes to, say, deciding between alternative ways of solving a problem or completing a task?” In all cases, we optimize for efficiency: We care about time or space.
Note the mention of “deciding between.” Computer scientists do that all the time, and I was convinced that the tools they use to evaluate competing algorithms would be of interest to a broad audience.
Why did you write this book, and who can benefit from it?
All the books I came across that tried to introduce computer science involved coding. My approach to making algorithms compelling was focusing on comparisons. I take algorithms and put them in a scene from everyday life, such as matching socks from a pile, putting books on a shelf, remembering things, driving from one point to another, or cutting an onion. These activities can be mapped to one or more fundamental algorithms, which form the basis for the field of computing and have far-reaching applications and uses.
I wrote the book with two audiences in mind. One, anyone, be it a learner or an educator, who is interested in computer science and wants an engaging and lighthearted, but not a dumbed-down, introduction to the field. Two, anyone who is already familiar with the field and wants to experience a way of explaining some of the fundamental concepts in computer science differently than how they’re taught.
I’m going to the grocery store and only have 15 minutes. What do I do?
Do you know what the grocery store looks like ahead of time? If you know what it looks like, it determines your list. How do you prioritize things on your list? Order the items in a way that allows you to avoid walking down the same aisles twice.
For me, the intriguing thing is that the grocery store is a scene from everyday life that I can use as a launch pad to talk about various related topics, like priority queues and graphs and hashing. For instance, what is the most efficient way for a machine to store a prioritized list, and what happens when the equivalent of you scratching an item from a list happens in the machine’s list? How is a store analogous to a graph (an abstraction in computer science and mathematics that defines how things are connected), and how is navigating the aisles in a store analogous to traversing a graph?
Nobody follows me on Instagram. How do I get more followers?
The concept of links and networks, which I cover in Chapter 6, is relevant here. It’s much easier to get to people whom you might be interested in and who might be interested in you if you can start within the ball of links that connects those people, rather than starting at a random spot.
You mention Instagram: There, the hashtag is one way to enter that ball of links. Tag your photos, engage with users who tag their photos with the same hashtags, and you should be on your way to stardom.
What are the secret ingredients of a successful Facebook post?
I’ve posted things on social media that have died a sad death and then posted the same thing at a later date that somehow did great. Again, if we think of it in terms that are relevant to algorithms, we’d say that the challenge with making something go viral is really getting that first spark. And to get that first spark, a person who is connected to the largest number of people who are likely to engage with that post, needs to share it.
With [my first book], “Bad Arguments,” I spent a month pouring close to $5,000 into advertising for that project with moderate results. And then one science journalist with a large audience wrote about it, and the project took off and hasn’t stopped since.
What problems do you wish you could solve via algorithm but can’t?
When we care about efficiency, thinking in terms of algorithms is useful. There are cases when that’s not the quality we want to optimize for — for instance, learning or love. I walk for several miles every day, all throughout the city, as I find it relaxing. I’ve never asked myself, “What’s the most efficient way I can traverse the streets of San Francisco?” It’s not relevant to my objective.
Algorithms are a great way of thinking about efficiency, but the question has to be, “What approach can you optimize for that objective?” That’s what worries me about self-help: Books give you a silver bullet for doing everything “right” but leave out all the nuances that make us different. What works for you might not work for me.
Which companies use algorithms well?
When you read that the overwhelming majority of the shows that users of, say, Netflix, watch are due to Netflix’s recommendation engine, you know they’re doing something right.