1635241170
It's not new news at all. Which Google for Work Applications and Microsoft Office have been conflicting with respect to rivalry. In the meantime, as Microsoft Office 365 pushes ahead, Google has dug in on its own initiatives. Organizations who sign an undertaking Concurrence with Microsoft also receive ideas from Google such as cutting costs, providing guidance the use of accessories. An Endeavor Understanding is where an organization is able to contract with organizations for a certain amount of time, usually three years, with the intention that the organization develops an adherence to Microsoft's policies. In addition, it is the place Google must strike. office.com/setup
The offer was made available in October of 2015, in the time that Google Applications were given out at no cost, in conjunction with Microsoft Office and the association's Endeavor Understandings.
In the beginning, Google's inside man service was initially proposed to medium - to large-scale organizations that were looking for alternatives in relation to Microsoft Office, in any situation, the plan was not without a caveat. Organizations who used Google Applications for Work expected to accept the game plan for using it for one year after it was decided that the Endeavor Consensus with Microsoft was concluded. Paying the standard $5 or $10 per user. This is fascinating considering the charge of $8 per customer which Microsoft Office 365 had completed. As reported by Business Insider, Google even paid associates of businesses out of their own pockets to assist in spreading the cost of getting new customers ready using Google Applications.
Google Applications Google Applications being alluded to are actually implied in the words. The gap was intentional in order to create something 'on-the-ball however, it was not enough for some clients who like to have the consistency and features Microsoft offers. The goal was not to force applications on users, but or for associations to influence themselves through distributing the application in a flurry.
Office 365 rising snappier than Google Applications still/Picture credit to Business Insider
It wasn't long it was revealed that Microsoft Financial Year 2016 Quarterly Report revealed that the number of customers who were dynamic specialists grew by 60 million. Both applications were making the same layout, according to a report to Business Insider, yet Microsoft Office was simultaneously being utilized more frequently than Google applications that were in a close relationship. However, the advancement in the performance of Google for Work wasn't sufficient to be considered a sufficient improvement for users at the Applications gathering. On Tuesday, they've revealed that the more modest organizations with up to 100 clients can consent to sign its inside-man contract.
In a field in which they're becoming more qualified companies, small and new associations tend to lean towards Google for Work appeared differently with respect to the cost of getting Microsoft programming. Even if it is to be a little difficult, Google has seen some improvements and is probably not going to cease looking the tests any time soon and not later. www.office.com/myaccount
1586415180
Instagram is the fastest-growing social network, with 1 billion monthly users. It also has the highest engagement rate. To gain followers on Instagram, you’d have to upload engaging content, follow users, like posts, comment on user posts and a whole lot. This can be time-consuming and daunting. But there is hope, you can automate all of these tasks. In this course, we’re going to build an Instagram bot using Python to automate tasks on Instagram.
What you’ll learn:
I got around 500 real followers in 4 days!
Growing an audience is an expensive and painful task. And if you’d like to build an audience that’s relevant to you, and shares common interests, that’s even more difficult. I always saw Instagram has a great way to promote my photos, but I never had more than 380 followers… Every once in a while, I decide to start posting my photos on Instagram again, and I manage to keep posting regularly for a while, but it never lasts more than a couple of months, and I don’t have many followers to keep me motivated and engaged.
The objective of this project is to build a bigger audience and as a plus, maybe drive some traffic to my website where I sell my photos!
A year ago, on my last Instagram run, I got one of those apps that lets you track who unfollowed you. I was curious because in a few occasions my number of followers dropped for no apparent reason. After some research, I realized how some users basically crawl for followers. They comment, like and follow people — looking for a follow back. Only to unfollow them again in the next days.
I can’t say this was a surprise to me, that there were bots in Instagram… It just made me want to build one myself!
And that is why we’re here, so let’s get to it! I came up with a simple bot in Python, while I was messing around with Selenium and trying to figure out some project to use it. Simply put, Selenium is like a browser you can interact with very easily in Python.
Ideally, increasing my Instagram audience will keep me motivated to post regularly. As an extra, I included my website in my profile bio, where people can buy some photos. I think it is a bit of a stretch, but who knows?! My sales are basically zero so far, so it should be easy to track that conversion!
After giving this project some thought, my objective was to increase my audience with relevant people. I want to get followers that actually want to follow me and see more of my work. It’s very easy to come across weird content in the most used hashtags, so I’ve planed this bot to lookup specific hashtags and interact with the photos there. This way, I can be very specific about what kind of interests I want my audience to have. For instance, I really like long exposures, so I can target people who use that hashtag and build an audience around this kind of content. Simple and efficient!
My gallery is a mix of different subjects and styles, from street photography to aerial photography, and some travel photos too. Since it’s my hometown, I also have lots of Lisbon images there. These will be the main topics I’ll use in the hashtags I want to target.
This is not a “get 1000 followers in 24 hours” kind of bot!
I ran the bot a few times in a few different hashtags like “travelblogger”, “travelgram”, “lisbon”, “dronephotography”. In the course of three days I went from 380 to 800 followers. Lots of likes, comments and even some organic growth (people that followed me but were not followed by the bot).
To be clear, I’m not using this bot intensively, as Instagram will stop responding if you run it too fast. It needs to have some sleep commands in between the actions, because after some comments and follows in a short period of time, Instagram stops responding and the bot crashes.
You will be logged into your account, so I’m almost sure that Instagram can know you’re doing something weird if you speed up the process. And most importantly, after doing this for a dozen hashtags, it just gets harder to find new users in the same hashtags. You will need to give it a few days to refresh the user base there.
The most efficient way to get followers in Instagram (apart from posting great photos!) is to follow people. And this bot worked really well for me because I don’t care if I follow 2000 people to get 400 followers.
The bot saves a list with all the users that were followed while it was running, so someday I may actually do something with this list. For instance, I can visit each user profile, evaluate how many followers or posts they have, and decide if I want to keep following them. Or I can get the first picture in their gallery and check its date to see if they are active users.
If we remove the follow action from the bot, I can assure you the growth rate will suffer, as people are less inclined to follow based on a single like or comment.
That’s the debate I had with myself. Even though I truly believe in giving back to the community (I still learn a lot from it too!), there are several paid platforms that do more or less the same as this project. Some are shady, some are used by celebrities. The possibility of starting a similar platform myself, is not off the table yet, so why make the code available?
With that in mind, I decided to add an extra level of difficulty to the process, so I was going to post the code below as an image. I wrote “was”, because meanwhile, I’ve realized the image I’m getting is low quality. Which in turn made me reconsider and post the gist. I’m that nice! The idea behind the image was that if you really wanted to use it, you would have to type the code yourself. And that was my way of limiting the use of this tool to people that actually go through the whole process to create it and maybe even improve it.
I learn a lot more when I type the code myself, instead of copy/pasting scripts. I hope you feel the same way!
The script isn’t as sophisticated as it could be, and I know there’s lots of room to improve it. But hey… it works! I have other projects I want to add to my portfolio, so my time to develop it further is rather limited. Nevertheless, I will try to update this article if I dig deeper.
You’ll need Python (I’m using Python 3.7), Selenium, a browser (in my case I’ll be using Chrome) and… obviously, an Instagram account! Quick overview regarding what the bot will do:
If you reached this paragraph, thank you! You totally deserve to collect your reward! If you find this useful for your profile/brand in any way, do share your experience below :)
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from time import sleep, strftime
from random import randint
import pandas as pd
chromedriver_path = 'C:/Users/User/Downloads/chromedriver_win32/chromedriver.exe' # Change this to your own chromedriver path!
webdriver = webdriver.Chrome(executable_path=chromedriver_path)
sleep(2)
webdriver.get('https://www.instagram.com/accounts/login/?source=auth_switcher')
sleep(3)
username = webdriver.find_element_by_name('username')
username.send_keys('your_username')
password = webdriver.find_element_by_name('password')
password.send_keys('your_password')
button_login = webdriver.find_element_by_css_selector('#react-root > section > main > div > article > div > div:nth-child(1) > div > form > div:nth-child(3) > button')
button_login.click()
sleep(3)
notnow = webdriver.find_element_by_css_selector('body > div:nth-child(13) > div > div > div > div.mt3GC > button.aOOlW.HoLwm')
notnow.click() #comment these last 2 lines out, if you don't get a pop up asking about notifications
In order to use chrome with Selenium, you need to install chromedriver. It’s a fairly simple process and I had no issues with it. Simply install and replace the path above. Once you do that, our variable webdriver will be our Chrome tab.
In cell number 3 you should replace the strings with your own username and the respective password. This is for the bot to type it in the fields displayed. You might have already noticed that when running cell number 2, Chrome opened a new tab. After the password, I’ll define the login button as an object, and in the following line, I click it.
Once you get in inspect mode find the bit of html code that corresponds to what you want to map. Right click it and hover over Copy. You will see that you have some options regarding how you want it to be copied. I used a mix of XPath and css selectors throughout the code (it’s visible in the find_element_ method). It took me a while to get all the references to run smoothly. At points, the css or the xpath directions would fail, but as I adjusted the sleep times, everything started running smoothly.
In this case, I selected “copy selector” and pasted it inside a find_element_ method (cell number 3). It will get you the first result it finds. If it was find_elements_, all elements would be retrieved and you could specify which to get.
Once you get that done, time for the loop. You can add more hashtags in the hashtag_list. If you run it for the first time, you still don’t have a file with the users you followed, so you can simply create prev_user_list as an empty list.
Once you run it once, it will save a csv file with a timestamp with the users it followed. That file will serve as the prev_user_list on your second run. Simple and easy to keep track of what the bot does.
Update with the latest timestamp on the following runs and you get yourself a series of csv backlogs for every run of the bot.
The code is really simple. If you have some basic notions of Python you can probably pick it up quickly. I’m no Python ninja and I was able to build it, so I guess that if you read this far, you are good to go!
hashtag_list = ['travelblog', 'travelblogger', 'traveler']
# prev_user_list = [] - if it's the first time you run it, use this line and comment the two below
prev_user_list = pd.read_csv('20181203-224633_users_followed_list.csv', delimiter=',').iloc[:,1:2] # useful to build a user log
prev_user_list = list(prev_user_list['0'])
new_followed = []
tag = -1
followed = 0
likes = 0
comments = 0
for hashtag in hashtag_list:
tag += 1
webdriver.get('https://www.instagram.com/explore/tags/'+ hashtag_list[tag] + '/')
sleep(5)
first_thumbnail = webdriver.find_element_by_xpath('//*[@id="react-root"]/section/main/article/div[1]/div/div/div[1]/div[1]/a/div')
first_thumbnail.click()
sleep(randint(1,2))
try:
for x in range(1,200):
username = webdriver.find_element_by_xpath('/html/body/div[3]/div/div[2]/div/article/header/div[2]/div[1]/div[1]/h2/a').text
if username not in prev_user_list:
# If we already follow, do not unfollow
if webdriver.find_element_by_xpath('/html/body/div[3]/div/div[2]/div/article/header/div[2]/div[1]/div[2]/button').text == 'Follow':
webdriver.find_element_by_xpath('/html/body/div[3]/div/div[2]/div/article/header/div[2]/div[1]/div[2]/button').click()
new_followed.append(username)
followed += 1
# Liking the picture
button_like = webdriver.find_element_by_xpath('/html/body/div[3]/div/div[2]/div/article/div[2]/section[1]/span[1]/button/span')
button_like.click()
likes += 1
sleep(randint(18,25))
# Comments and tracker
comm_prob = randint(1,10)
print('{}_{}: {}'.format(hashtag, x,comm_prob))
if comm_prob > 7:
comments += 1
webdriver.find_element_by_xpath('/html/body/div[3]/div/div[2]/div/article/div[2]/section[1]/span[2]/button/span').click()
comment_box = webdriver.find_element_by_xpath('/html/body/div[3]/div/div[2]/div/article/div[2]/section[3]/div/form/textarea')
if (comm_prob < 7):
comment_box.send_keys('Really cool!')
sleep(1)
elif (comm_prob > 6) and (comm_prob < 9):
comment_box.send_keys('Nice work :)')
sleep(1)
elif comm_prob == 9:
comment_box.send_keys('Nice gallery!!')
sleep(1)
elif comm_prob == 10:
comment_box.send_keys('So cool! :)')
sleep(1)
# Enter to post comment
comment_box.send_keys(Keys.ENTER)
sleep(randint(22,28))
# Next picture
webdriver.find_element_by_link_text('Next').click()
sleep(randint(25,29))
else:
webdriver.find_element_by_link_text('Next').click()
sleep(randint(20,26))
# some hashtag stops refreshing photos (it may happen sometimes), it continues to the next
except:
continue
for n in range(0,len(new_followed)):
prev_user_list.append(new_followed[n])
updated_user_df = pd.DataFrame(prev_user_list)
updated_user_df.to_csv('{}_users_followed_list.csv'.format(strftime("%Y%m%d-%H%M%S")))
print('Liked {} photos.'.format(likes))
print('Commented {} photos.'.format(comments))
print('Followed {} new people.'.format(followed))
The print statement inside the loop is the way I found to be able to have a tracker that lets me know at what iteration the bot is all the time. It will print the hashtag it’s in, the number of the iteration, and the random number generated for the comment action. I decided not to post comments in every page, so I added three different comments and a random number between 1 and 10 that would define if there was any comment at all, or one of the three. The loop ends, we append the new_followed users to the previous users “database” and saves the new file with the timestamp. You should also get a small report.
And that’s it!
After a few hours without checking the phone, these were the numbers I was getting. I definitely did not expect it to do so well! In about 4 days since I’ve started testing it, I had around 500 new followers, which means I have doubled my audience in a matter of days. I’m curious to see how many of these new followers I will lose in the next days, to see if the growth can be sustainable. I also had a lot more “likes” in my latest photos, but I guess that’s even more expected than the follow backs.
It would be nice to get this bot running in a server, but I have other projects I want to explore, and configuring a server is not one of them! Feel free to leave a comment below, and I’ll do my best to answer your questions.
I’m actually curious to see how long will I keep posting regularly! If you feel like this article was helpful for you, consider thanking me by buying one of my photos.
What do SocialCaptain, Kicksta, Instavast, and many other companies have in common? They all help you reach a greater audience, gain more followers, and get more likes on Instagram while you hardly lift a finger. They do it all through automation, and people pay them a good deal of money for it. But you can do the same thing—for free—using InstaPy!
In this tutorial, you’ll learn how to build a bot with Python and InstaPy, which automates your Instagram activities so that you gain more followers and likes with minimal manual input. Along the way, you’ll learn about browser automation with Selenium and the Page Object Pattern, which together serve as the basis for InstaPy.
In this tutorial, you’ll learn:
You’ll begin by learning how Instagram bots work before you build one.
Table of Contents
Important: Make sure you check Instagram’s Terms of Use before implementing any kind of automation or scraping techniques.
How can an automation script gain you more followers and likes? Before answering this question, think about how an actual person gains more followers and likes.
They do it by being consistently active on the platform. They post often, follow other people, and like and leave comments on other people’s posts. Bots work exactly the same way: They follow, like, and comment on a consistent basis according to the criteria you set.
The better the criteria you set, the better your results will be. You want to make sure you’re targeting the right groups because the people your bot interacts with on Instagram will be more likely to interact with your content.
For example, if you’re selling women’s clothing on Instagram, then you can instruct your bot to like, comment on, and follow mostly women or profiles whose posts include hashtags such as #beauty
, #fashion
, or #clothes
. This makes it more likely that your target audience will notice your profile, follow you back, and start interacting with your posts.
How does it work on the technical side, though? You can’t use the Instagram Developer API since it is fairly limited for this purpose. Enter browser automation. It works in the following way:
https://instagram.com
on the address bar, logs in with your credentials, and starts doing the things you instructed it to do.Next, you’ll build the initial version of your Instagram bot, which will automatically log in to your profile. Note that you won’t use InstaPy just yet.
For this version of your Instagram bot, you’ll be using Selenium, which is the tool that InstaPy uses under the hood.
First, install Selenium. During installation, make sure you also install the Firefox WebDriver since the latest version of InstaPy dropped support for Chrome. This also means that you need the Firefox browser installed on your computer.
Now, create a Python file and write the following code in it:
from time import sleep
from selenium import webdriver
browser = webdriver.Firefox()
browser.get('https://www.instagram.com/')
sleep(5)
browser.close()
Run the code and you’ll see that a Firefox browser opens and directs you to the Instagram login page. Here’s a line-by-line breakdown of the code:
sleep
and webdriver
.browser
.https://www.instagram.com/
on the address bar and hits Enter.This is the Selenium version of Hello, World
. Now you’re ready to add the code that logs in to your Instagram profile. But first, think about how you would log in to your profile manually. You would do the following:
https://www.instagram.com/
.The first step is already done by the code above. Now change it so that it clicks on the login link on the Instagram home page:
from time import sleep
from selenium import webdriver
browser = webdriver.Firefox()
browser.implicitly_wait(5)
browser.get('https://www.instagram.com/')
login_link = browser.find_element_by_xpath("//a[text()='Log in']")
login_link.click()
sleep(5)
browser.close()
Note the highlighted lines:
<a>
whose text is equal to Log in
. It does this using XPath, but there are a few other methods you could use.<a>
for the login link.Run the script and you’ll see your script in action. It will open the browser, go to Instagram, and click on the login link to go to the login page.
On the login page, there are three important elements:
Next, change the script so that it finds those elements, enters your credentials, and clicks on the login button:
from time import sleep
from selenium import webdriver
browser = webdriver.Firefox()
browser.implicitly_wait(5)
browser.get('https://www.instagram.com/')
login_link = browser.find_element_by_xpath("//a[text()='Log in']")
login_link.click()
sleep(2)
username_input = browser.find_element_by_css_selector("input[name='username']")
password_input = browser.find_element_by_css_selector("input[name='password']")
username_input.send_keys("<your username>")
password_input.send_keys("<your password>")
login_button = browser.find_element_by_xpath("//button[@type='submit']")
login_button.click()
sleep(5)
browser.close()
Here’s a breakdown of the changes:
<your username>
and <your password>
!Run the script and you’ll be automatically logged in to to your Instagram profile.
You’re off to a good start with your Instagram bot. If you were to continue writing this script, then the rest would look very similar. You would find the posts that you like by scrolling down your feed, find the like button by CSS, click on it, find the comments section, leave a comment, and continue.
The good news is that all of those steps can be handled by InstaPy. But before you jump into using Instapy, there is one other thing that you should know about to better understand how InstaPy works: the Page Object Pattern.
Now that you’ve written the login code, how would you write a test for it? It would look something like the following:
def test_login_page(browser):
browser.get('https://www.instagram.com/accounts/login/')
username_input = browser.find_element_by_css_selector("input[name='username']")
password_input = browser.find_element_by_css_selector("input[name='password']")
username_input.send_keys("<your username>")
password_input.send_keys("<your password>")
login_button = browser.find_element_by_xpath("//button[@type='submit']")
login_button.click()
errors = browser.find_elements_by_css_selector('#error_message')
assert len(errors) == 0
Can you see what’s wrong with this code? It doesn’t follow the DRY principle. That is, the code is duplicated in both the application and the test code.
Duplicating code is especially bad in this context because Selenium code is dependent on UI elements, and UI elements tend to change. When they do change, you want to update your code in one place. That’s where the Page Object Pattern comes in.
With this pattern, you create page object classes for the most important pages or fragments that provide interfaces that are straightforward to program to and that hide the underlying widgetry in the window. With this in mind, you can rewrite the code above and create a HomePage
class and a LoginPage
class:
from time import sleep
class LoginPage:
def __init__(self, browser):
self.browser = browser
def login(self, username, password):
username_input = self.browser.find_element_by_css_selector("input[name='username']")
password_input = self.browser.find_element_by_css_selector("input[name='password']")
username_input.send_keys(username)
password_input.send_keys(password)
login_button = browser.find_element_by_xpath("//button[@type='submit']")
login_button.click()
sleep(5)
class HomePage:
def __init__(self, browser):
self.browser = browser
self.browser.get('https://www.instagram.com/')
def go_to_login_page(self):
self.browser.find_element_by_xpath("//a[text()='Log in']").click()
sleep(2)
return LoginPage(self.browser)
The code is the same except that the home page and the login page are represented as classes. The classes encapsulate the mechanics required to find and manipulate the data in the UI. That is, there are methods and accessors that allow the software to do anything a human can.
One other thing to note is that when you navigate to another page using a page object, it returns a page object for the new page. Note the returned value of go_to_log_in_page()
. If you had another class called FeedPage
, then login()
of the LoginPage
class would return an instance of that: return FeedPage()
.
Here’s how you can put the Page Object Pattern to use:
from selenium import webdriver
browser = webdriver.Firefox()
browser.implicitly_wait(5)
home_page = HomePage(browser)
login_page = home_page.go_to_login_page()
login_page.login("<your username>", "<your password>")
browser.close()
It looks much better, and the test above can now be rewritten to look like this:
def test_login_page(browser):
home_page = HomePage(browser)
login_page = home_page.go_to_login_page()
login_page.login("<your username>", "<your password>")
errors = browser.find_elements_by_css_selector('#error_message')
assert len(errors) == 0
With these changes, you won’t have to touch your tests if something changes in the UI.
For more information on the Page Object Pattern, refer to the official documentation and to Martin Fowler’s article.
Now that you’re familiar with both Selenium and the Page Object Pattern, you’ll feel right at home with InstaPy. You’ll build a basic bot with it next.
Note: Both Selenium and the Page Object Pattern are widely used for other websites, not just for Instagram.
In this section, you’ll use InstaPy to build an Instagram bot that will automatically like, follow, and comment on different posts. First, you’ll need to install InstaPy:
$ python3 -m pip install instapy
This will install instapy
in your system.
Now you can rewrite the code above with InstaPy so that you can compare the two options. First, create another Python file and put the following code in it:
from instapy import InstaPy
InstaPy(username="<your_username>", password="<your_password>").login()
Replace the username and password with yours, run the script, and voilà! With just one line of code, you achieved the same result.
Even though your results are the same, you can see that the behavior isn’t exactly the same. In addition to simply logging in to your profile, InstaPy does some other things, such as checking your internet connection and the status of the Instagram servers. This can be observed directly on the browser or in the logs:
INFO [2019-12-17 22:03:19] [username] -- Connection Checklist [1/3] (Internet Connection Status)
INFO [2019-12-17 22:03:20] [username] - Internet Connection Status: ok
INFO [2019-12-17 22:03:20] [username] - Current IP is "17.283.46.379" and it's from "Germany/DE"
INFO [2019-12-17 22:03:20] [username] -- Connection Checklist [2/3] (Instagram Server Status)
INFO [2019-12-17 22:03:26] [username] - Instagram WebSite Status: Currently Up
Pretty good for one line of code, isn’t it? Now it’s time to make the script do more interesting things than just logging in.
For the purpose of this example, assume that your profile is all about cars, and that your bot is intended to interact with the profiles of people who are also interested in cars.
First, you can like some posts that are tagged #bmw
or #mercedes
using like_by_tags()
:
from instapy import InstaPy
session = InstaPy(username="<your_username>", password="<your_password>")
session.login()
session.like_by_tags(["bmw", "mercedes"], amount=5)
Here, you gave the method a list of tags to like and the number of posts to like for each given tag. In this case, you instructed it to like ten posts, five for each of the two tags. But take a look at what happens after you run the script:
INFO [2019-12-17 22:15:58] [username] Tag [1/2]
INFO [2019-12-17 22:15:58] [username] --> b'bmw'
INFO [2019-12-17 22:16:07] [username] desired amount: 14 | top posts [disabled]: 9 | possible posts: 43726739
INFO [2019-12-17 22:16:13] [username] Like# [1/14]
INFO [2019-12-17 22:16:13] [username] https://www.instagram.com/p/B6MCcGcC3tU/
INFO [2019-12-17 22:16:15] [username] Image from: b'mattyproduction'
INFO [2019-12-17 22:16:15] [username] Link: b'https://www.instagram.com/p/B6MCcGcC3tU/'
INFO [2019-12-17 22:16:15] [username] Description: b'Mal etwas anderes \xf0\x9f\x91\x80\xe2\x98\xba\xef\xb8\x8f Bald ist das komplette Video auf YouTube zu finden (n\xc3\xa4here Infos werden folgen). Vielen Dank an @patrick_jwki @thehuthlife und @christic_ f\xc3\xbcr das bereitstellen der Autos \xf0\x9f\x94\xa5\xf0\x9f\x98\x8d#carporn#cars#tuning#bagged#bmw#m2#m2competition#focusrs#ford#mk3#e92#m3#panasonic#cinematic#gh5s#dji#roninm#adobe#videography#music#bimmer#fordperformance#night#shooting#'
INFO [2019-12-17 22:16:15] [username] Location: b'K\xc3\xb6ln, Germany'
INFO [2019-12-17 22:16:51] [username] --> Image Liked!
INFO [2019-12-17 22:16:56] [username] --> Not commented
INFO [2019-12-17 22:16:57] [username] --> Not following
INFO [2019-12-17 22:16:58] [username] Like# [2/14]
INFO [2019-12-17 22:16:58] [username] https://www.instagram.com/p/B6MDK1wJ-Kb/
INFO [2019-12-17 22:17:01] [username] Image from: b'davs0'
INFO [2019-12-17 22:17:01] [username] Link: b'https://www.instagram.com/p/B6MDK1wJ-Kb/'
INFO [2019-12-17 22:17:01] [username] Description: b'Someone said cloud? \xf0\x9f\xa4\x94\xf0\x9f\xa4\xad\xf0\x9f\x98\x88 \xe2\x80\xa2\n\xe2\x80\xa2\n\xe2\x80\xa2\n\xe2\x80\xa2\n#bmw #bmwrepost #bmwm4 #bmwm4gts #f82 #bmwmrepost #bmwmsport #bmwmperformance #bmwmpower #bmwm4cs #austinyellow #davs0 #mpower_official #bmw_world_ua #bimmerworld #bmwfans #bmwfamily #bimmers #bmwpost #ultimatedrivingmachine #bmwgang #m3f80 #m5f90 #m4f82 #bmwmafia #bmwcrew #bmwlifestyle'
INFO [2019-12-17 22:17:34] [username] --> Image Liked!
INFO [2019-12-17 22:17:37] [username] --> Not commented
INFO [2019-12-17 22:17:38] [username] --> Not following
By default, InstaPy will like the first nine top posts in addition to your amount
value. In this case, that brings the total number of likes per tag to fourteen (nine top posts plus the five you specified in amount
).
Also note that InstaPy logs every action it takes. As you can see above, it mentions which post it liked as well as its link, description, location, and whether the bot commented on the post or followed the author.
You may have noticed that there are delays after almost every action. That’s by design. It prevents your profile from getting banned on Instagram.
Now, you probably don’t want your bot liking inappropriate posts. To prevent that from happening, you can use set_dont_like()
:
from instapy import InstaPy
session = InstaPy(username="<your_username>", password="<your_password>")
session.login()
session.like_by_tags(["bmw", "mercedes"], amount=5)
session.set_dont_like(["naked", "nsfw"])
With this change, posts that have the words naked
or nsfw
in their descriptions won’t be liked. You can flag any other words that you want your bot to avoid.
Next, you can tell the bot to not only like the posts but also to follow some of the authors of those posts. You can do that with set_do_follow()
:
from instapy import InstaPy
session = InstaPy(username="<your_username>", password="<your_password>")
session.login()
session.like_by_tags(["bmw", "mercedes"], amount=5)
session.set_dont_like(["naked", "nsfw"])
session.set_do_follow(True, percentage=50)
If you run the script now, then the bot will follow fifty percent of the users whose posts it liked. As usual, every action will be logged.
You can also leave some comments on the posts. There are two things that you need to do. First, enable commenting with set_do_comment()
:
from instapy import InstaPy
session = InstaPy(username="<your_username>", password="<your_password>")
session.login()
session.like_by_tags(["bmw", "mercedes"], amount=5)
session.set_dont_like(["naked", "nsfw"])
session.set_do_follow(True, percentage=50)
session.set_do_comment(True, percentage=50)
Next, tell the bot what comments to leave with set_comments()
:
from instapy import InstaPy
session = InstaPy(username="<your_username>", password="<your_password>")
session.login()
session.like_by_tags(["bmw", "mercedes"], amount=5)
session.set_dont_like(["naked", "nsfw"])
session.set_do_follow(True, percentage=50)
session.set_do_comment(True, percentage=50)
session.set_comments(["Nice!", "Sweet!", "Beautiful :heart_eyes:"])
Run the script and the bot will leave one of those three comments on half the posts that it interacts with.
Now that you’re done with the basic settings, it’s a good idea to end the session with end()
:
from instapy import InstaPy
session = InstaPy(username="<your_username>", password="<your_password>")
session.login()
session.like_by_tags(["bmw", "mercedes"], amount=5)
session.set_dont_like(["naked", "nsfw"])
session.set_do_follow(True, percentage=50)
session.set_do_comment(True, percentage=50)
session.set_comments(["Nice!", "Sweet!", "Beautiful :heart_eyes:"])
session.end()
This will close the browser, save the logs, and prepare a report that you can see in the console output.
InstaPy is a sizable project that has a lot of thoroughly documented features. The good news is that if you’re feeling comfortable with the features you used above, then the rest should feel pretty similar. This section will outline some of the more useful features of InstaPy.
You can’t scrape Instagram all day, every day. The service will quickly notice that you’re running a bot and will ban some of its actions. That’s why it’s a good idea to set quotas on some of your bot’s actions. Take the following for example:
session.set_quota_supervisor(enabled=True, peak_comments_daily=240, peak_comments_hourly=21)
The bot will keep commenting until it reaches its hourly and daily limits. It will resume commenting after the quota period has passed.
This feature allows you to run your bot without the GUI of the browser. This is super useful if you want to deploy your bot to a server where you may not have or need the graphical interface. It’s also less CPU intensive, so it improves performance. You can use it like so:
session = InstaPy(username='test', password='test', headless_browser=True)
Note that you set this flag when you initialize the InstaPy
object.
Earlier you saw how to ignore posts that contain inappropriate words in their descriptions. What if the description is good but the image itself is inappropriate? You can integrate your InstaPy bot with ClarifAI, which offers image and video recognition services:
session.set_use_clarifai(enabled=True, api_key='<your_api_key>')
session.clarifai_check_img_for(['nsfw'])
Now your bot won’t like or comment on any image that ClarifAI considers NSFW. You get 5,000 free API-calls per month.
It’s often a waste of time to interact with posts by people who have a lot of followers. In such cases, it’s a good idea to set some relationship bounds so that your bot doesn’t waste your precious computing resources:
session.set_relationship_bounds(enabled=True, max_followers=8500)
With this, your bot won’t interact with posts by users who have more than 8,500 followers.
For many more features and configurations in InstaPy, check out the documentation.
InstaPy allows you to automate your Instagram activities with minimal fuss and effort. It’s a very flexible tool with a lot of useful features.
In this tutorial, you learned:
Read the InstaPy documentation and experiment with your bot a little bit. Soon you’ll start getting new followers and likes with a minimal amount of effort. I gained a few new followers myself while writing this tutorial.
Maybe some of you do not agree it is a good way to grow your IG page by using follow for follow method but after a lot of researching I found the proper way to use this method.
I have done and used this strategy for a while and my page visits also followers started growing.
The majority of people failing because they randomly targeting the followers and as a result, they are not coming back to your page. So, the key is to find people those have same interests with you.
If you have a programming page go and search for IG pages which have big programming community and once you find one, don’t send follow requests to followers of this page. Because some of them are not active even maybe fake accounts. So, in order to gain active followers, go the last post of this page and find people who liked the post.
In order to query data from Instagram I am going to use the very cool, yet unofficial, Instagram API written by Pasha Lev.
**Note:**Before you test it make sure you verified your phone number in your IG account.
The program works pretty well so far but in case of any problems I have to put disclaimer statement here:
Disclaimer: This post published educational purposes only as well as to give general information about Instagram API. I am not responsible for any actions and you are taking your own risk.
Let’s start by installing and then logging in with API.
pip install InstagramApi
from InstagramAPI import InstagramAPI
api = InstagramAPI("username", "password")
api.login()
Once you run the program you will see “Login success!” in your console.
We are going to search for some username (your target page) then get most recent post from this user. Then, get users who liked this post. Unfortunately, I can’t find solution how to paginate users so right now it gets about last 500 user.
users_list = []
def get_likes_list(username):
api.login()
api.searchUsername(username)
result = api.LastJson
username_id = result['user']['pk'] # Get user ID
user_posts = api.getUserFeed(username_id) # Get user feed
result = api.LastJson
media_id = result['items'][0]['id'] # Get most recent post
api.getMediaLikers(media_id) # Get users who liked
users = api.LastJson['users']
for user in users: # Push users to list
users_list.append({'pk':user['pk'], 'username':user['username']})
Once we get the users list, it is time to follow these users.
IMPORTANT NOTE: set time limit as much as you can to avoid automation detection.
from time import sleep
following_users = []
def follow_users(users_list):
api.login()
api.getSelfUsersFollowing() # Get users which you are following
result = api.LastJson
for user in result['users']:
following_users.append(user['pk'])
for user in users_list:
if not user['pk'] in following_users: # if new user is not in your following users
print('Following @' + user['username'])
api.follow(user['pk'])
# after first test set this really long to avoid from suspension
sleep(20)
else:
print('Already following @' + user['username'])
sleep(10)
This function will look users which you are following then it will check if this user follows you as well. If user not following you then you are unfollowing as well.
follower_users = []
def unfollow_users():
api.login()
api.getSelfUserFollowers() # Get your followers
result = api.LastJson
for user in result['users']:
follower_users.append({'pk':user['pk'], 'username':user['username']})
api.getSelfUsersFollowing() # Get users which you are following
result = api.LastJson
for user in result['users']:
following_users.append({'pk':user['pk'],'username':user['username']})
for user in following_users:
if not user['pk'] in follower_users: # if the user not follows you
print('Unfollowing @' + user['username'])
api.unfollow(user['pk'])
# set this really long to avoid from suspension
sleep(20)
Here is the full code of this automation
import pprint
from time import sleep
from InstagramAPI import InstagramAPI
import pandas as pd
users_list = []
following_users = []
follower_users = []
class InstaBot:
def __init__(self):
self.api = InstagramAPI("your_username", "your_password")
def get_likes_list(self,username):
api = self.api
api.login()
api.searchUsername(username) #Gets most recent post from user
result = api.LastJson
username_id = result['user']['pk']
user_posts = api.getUserFeed(username_id)
result = api.LastJson
media_id = result['items'][0]['id']
api.getMediaLikers(media_id)
users = api.LastJson['users']
for user in users:
users_list.append({'pk':user['pk'], 'username':user['username']})
bot.follow_users(users_list)
def follow_users(self,users_list):
api = self.api
api.login()
api.getSelfUsersFollowing()
result = api.LastJson
for user in result['users']:
following_users.append(user['pk'])
for user in users_list:
if not user['pk'] in following_users:
print('Following @' + user['username'])
api.follow(user['pk'])
# set this really long to avoid from suspension
sleep(20)
else:
print('Already following @' + user['username'])
sleep(10)
def unfollow_users(self):
api = self.api
api.login()
api.getSelfUserFollowers()
result = api.LastJson
for user in result['users']:
follower_users.append({'pk':user['pk'], 'username':user['username']})
api.getSelfUsersFollowing()
result = api.LastJson
for user in result['users']:
following_users.append({'pk':user['pk'],'username':user['username']})
for user in following_users:
if not user['pk'] in [user['pk'] for user in follower_users]:
print('Unfollowing @' + user['username'])
api.unfollow(user['pk'])
# set this really long to avoid from suspension
sleep(20)
bot = InstaBot()
# To follow users run the function below
# change the username ('instagram') to your target username
bot.get_likes_list('instagram')
# To unfollow users uncomment and run the function below
# bot.unfollow_users()
it will look like this:
some extra functions to play with API:
def get_my_profile_details():
api.login()
api.getSelfUsernameInfo()
result = api.LastJson
username = result['user']['username']
full_name = result['user']['full_name']
profile_pic_url = result['user']['profile_pic_url']
followers = result['user']['follower_count']
following = result['user']['following_count']
media_count = result['user']['media_count']
df_profile = pd.DataFrame(
{'username':username,
'full name': full_name,
'profile picture URL':profile_pic_url,
'followers':followers,
'following':following,
'media count': media_count,
}, index=[0])
df_profile.to_csv('profile.csv', sep='\t', encoding='utf-8')
def get_my_feed():
image_urls = []
api.login()
api.getSelfUserFeed()
result = api.LastJson
# formatted_json_str = pprint.pformat(result)
# print(formatted_json_str)
if 'items' in result.keys():
for item in result['items'][0:5]:
if 'image_versions2' in item.keys():
image_url = item['image_versions2']['candidates'][1]['url']
image_urls.append(image_url)
df_feed = pd.DataFrame({
'image URL':image_urls
})
df_feed.to_csv('feed.csv', sep='\t', encoding='utf-8')
Let’s build an Instagram bot to gain more followers! — I know, I know. That doesn’t sound very ethical, does it? But it’s all justified for educational purposes.
Coding is a super power — we can all agree. That’s why I’ll leave it up to you to not abuse this power. And I trust you’re here to learn how it works. Otherwise, you’d be on GitHub cloning one of the countless Instagram bots there, right?
You’re convinced? — Alright, now let’s go back to unethical practices.
So here’s the deal, we want to build a bot in Python and Selenium that goes on the hashtags we specify, likes random posts, then follows the posters. It does that enough — we get follow backs. Simple as that.
Here’s a pretty twisted detail though: we want to keep track of the users we follow so the bot can unfollow them after the number of days we specify.
So first things first, I want to use a database to keep track of the username and the date added. You might as well save/load from/to a file, but we want this to be ready for more features in case we felt inspired in the future.
So make sure you create a database (I named mine instabot — but you can name it anything you like) and create a table called followed_users within the database with two fields (username, date_added)
Remember the installation path. You’ll need it.
You’ll also need the following python packages:
Alright, so first thing we’ll be doing is creating settings.json. Simply a .json file that will hold all of our settings so we don’t have to dive into the code every time we want to change something.
settings.json:
{
"db": {
"host": "localhost",
"user": "root",
"pass": "",
"database": "instabot"
},
"instagram": {
"user": "",
"pass": ""
},
"config": {
"days_to_unfollow": 1,
"likes_over": 150,
"check_followers_every": 3600,
"hashtags": []
}
}
As you can see, under “db”, we specify the database information. As I mentioned, I used “instabot”, but feel free to use whatever name you want.
You’ll also need to fill Instagram info under “instagram” so the bot can login into your account.
“config” is for our bot’s settings. Here’s what the fields mean:
days_to_unfollow: number of days before unfollowing users
likes_over: ignore posts if the number of likes is above this number
check_followers_every: number of seconds before checking if it’s time to unfollow any of the users
hashtags: a list of strings with the hashtag names the bot should be active on
Now, we want to take these settings and have them inside our code as constants.
Create Constants.py:
import json
INST_USER= INST_PASS= USER= PASS= HOST= DATABASE= POST_COMMENTS= ''
LIKES_LIMIT= DAYS_TO_UNFOLLOW= CHECK_FOLLOWERS_EVERY= 0
HASHTAGS= []
def init():
global INST_USER, INST_PASS, USER, PASS, HOST, DATABASE, LIKES_LIMIT, DAYS_TO_UNFOLLOW, CHECK_FOLLOWERS_EVERY, HASHTAGS
# read file
data = None
with open('settings.json', 'r') as myfile:
data = myfile.read()
obj = json.loads(data)
INST_USER = obj['instagram']['user']
INST_PASS = obj['instagram']['pass']
USER = obj['db']['user']
HOST = obj['db']['host']
PASS = obj['db']['pass']
DATABASE = obj['db']['database']
LIKES_LIMIT = obj['config']['likes_over']
CHECK_FOLLOWERS_EVERY = obj['config']['check_followers_every']
HASHTAGS = obj['config']['hashtags']
DAYS_TO_UNFOLLOW = obj['config']['days_to_unfollow']
the init() function we created reads the data from settings.json and feeds them into the constants we declared.
Alright, time for some architecture. Our bot will mainly operate from a python script with an init and update methods. Create BotEngine.py:
import Constants
def init(webdriver):
return
def update(webdriver):
return
We’ll be back later to put the logic here, but for now, we need an entry point.
Create our entry point, InstaBot.py:
from selenium import webdriver
import BotEngine
chromedriver_path = 'YOUR CHROMEDRIVER PATH'
webdriver = webdriver.Chrome(executable_path=chromedriver_path)
BotEngine.init(webdriver)
BotEngine.update(webdriver)
webdriver.close()
chromedriver_path = ‘YOUR CHROMEDRIVER PATH’ webdriver = webdriver.Chrome(executable_path=chromedriver_path)
BotEngine.init(webdriver)
BotEngine.update(webdriver)
webdriver.close()
Of course, you’ll need to swap “YOUR CHROMEDRIVER PATH” with your actual ChromeDriver path.
We need to create a helper script that will help us calculate elapsed days since a certain date (so we know if we should unfollow user)
Create TimeHelper.py:
import datetime
def days_since_date(n):
diff = datetime.datetime.now().date() - n
return diff.days
Create DBHandler.py. It’ll contain a class that handles connecting to the Database for us.
import mysql.connector
import Constants
class DBHandler:
def __init__(self):
DBHandler.HOST = Constants.HOST
DBHandler.USER = Constants.USER
DBHandler.DBNAME = Constants.DATABASE
DBHandler.PASSWORD = Constants.PASS
HOST = Constants.HOST
USER = Constants.USER
DBNAME = Constants.DATABASE
PASSWORD = Constants.PASS
@staticmethod
def get_mydb():
if DBHandler.DBNAME == '':
Constants.init()
db = DBHandler()
mydb = db.connect()
return mydb
def connect(self):
mydb = mysql.connector.connect(
host=DBHandler.HOST,
user=DBHandler.USER,
passwd=DBHandler.PASSWORD,
database = DBHandler.DBNAME
)
return mydb
As you can see, we’re using the constants we defined.
The class contains a static method get_mydb() that returns a database connection we can use.
Now, let’s define a DB user script that contains the DB operations we need to perform on the user.
Create DBUsers.py:
import datetime, TimeHelper
from DBHandler import *
import Constants
#delete user by username
def delete_user(username):
mydb = DBHandler.get_mydb()
cursor = mydb.cursor()
sql = "DELETE FROM followed_users WHERE username = '{0}'".format(username)
cursor.execute(sql)
mydb.commit()
#add new username
def add_user(username):
mydb = DBHandler.get_mydb()
cursor = mydb.cursor()
now = datetime.datetime.now().date()
cursor.execute("INSERT INTO followed_users(username, date_added) VALUES(%s,%s)",(username, now))
mydb.commit()
#check if any user qualifies to be unfollowed
def check_unfollow_list():
mydb = DBHandler.get_mydb()
cursor = mydb.cursor()
cursor.execute("SELECT * FROM followed_users")
results = cursor.fetchall()
users_to_unfollow = []
for r in results:
d = TimeHelper.days_since_date(r[1])
if d > Constants.DAYS_TO_UNFOLLOW:
users_to_unfollow.append(r[0])
return users_to_unfollow
#get all followed users
def get_followed_users():
users = []
mydb = DBHandler.get_mydb()
cursor = mydb.cursor()
cursor.execute("SELECT * FROM followed_users")
results = cursor.fetchall()
for r in results:
users.append(r[0])
return users
Alright, we’re about to start our bot. We’re creating a script called AccountAgent.py that will contain the agent behavior.
Import some modules, some of which we need for later and write a login function that will make use of our webdriver.
Notice that we have to keep calling the sleep function between actions. If we send too many requests quickly, the Instagram servers will be alarmed and will deny any requests you send.
from time import sleep
import datetime
import DBUsers, Constants
import traceback
import random
def login(webdriver):
#Open the instagram login page
webdriver.get('https://www.instagram.com/accounts/login/?source=auth_switcher')
#sleep for 3 seconds to prevent issues with the server
sleep(3)
#Find username and password fields and set their input using our constants
username = webdriver.find_element_by_name('username')
username.send_keys(Constants.INST_USER)
password = webdriver.find_element_by_name('password')
password.send_keys(Constants.INST_PASS)
#Get the login button
try:
button_login = webdriver.find_element_by_xpath(
'//*[@id="react-root"]/section/main/div/article/div/div[1]/div/form/div[4]/button')
except:
button_login = webdriver.find_element_by_xpath(
'//*[@id="react-root"]/section/main/div/article/div/div[1]/div/form/div[6]/button/div')
#sleep again
sleep(2)
#click login
button_login.click()
sleep(3)
#In case you get a popup after logging in, press not now.
#If not, then just return
try:
notnow = webdriver.find_element_by_css_selector(
'body > div.RnEpo.Yx5HN > div > div > div.mt3GC > button.aOOlW.HoLwm')
notnow.click()
except:
return
Also note how we’re getting elements with their xpath. To do so, right click on the element, click “Inspect”, then right click on the element again inside the inspector, and choose Copy->Copy XPath.
Another important thing to be aware of is that element hierarchy change with the page’s layout when you resize or stretch the window. That’s why we’re checking for two different xpaths for the login button.
Now go back to BotEngine.py, we’re ready to login.
Add more imports that we’ll need later and fill in the init function
import AccountAgent, DBUsers
import Constants
import datetime
def init(webdriver):
Constants.init()
AccountAgent.login(webdriver)
def update(webdriver):
return
If you run our entry script now (InstaBot.py) you’ll see the bot logging in.
Perfect, now let’s add a method that will allow us to follow people to AccountAgent.py:
def follow_people(webdriver):
#all the followed user
prev_user_list = DBUsers.get_followed_users()
#a list to store newly followed users
new_followed = []
#counters
followed = 0
likes = 0
#Iterate theough all the hashtags from the constants
for hashtag in Constants.HASHTAGS:
#Visit the hashtag
webdriver.get('https://www.instagram.com/explore/tags/' + hashtag+ '/')
sleep(5)
#Get the first post thumbnail and click on it
first_thumbnail = webdriver.find_element_by_xpath(
'//*[@id="react-root"]/section/main/article/div[1]/div/div/div[1]/div[1]/a/div')
first_thumbnail.click()
sleep(random.randint(1,3))
try:
#iterate over the first 200 posts in the hashtag
for x in range(1,200):
t_start = datetime.datetime.now()
#Get the poster's username
username = webdriver.find_element_by_xpath('/html/body/div[3]/div[2]/div/article/header/div[2]/div[1]/div[1]/h2/a').text
likes_over_limit = False
try:
#get number of likes and compare it to the maximum number of likes to ignore post
likes = int(webdriver.find_element_by_xpath(
'/html/body/div[3]/div[2]/div/article/div[2]/section[2]/div/div/button/span').text)
if likes > Constants.LIKES_LIMIT:
print("likes over {0}".format(Constants.LIKES_LIMIT))
likes_over_limit = True
print("Detected: {0}".format(username))
#If username isn't stored in the database and the likes are in the acceptable range
if username not in prev_user_list and not likes_over_limit:
#Don't press the button if the text doesn't say follow
if webdriver.find_element_by_xpath('/html/body/div[3]/div[2]/div/article/header/div[2]/div[1]/div[2]/button').text == 'Follow':
#Use DBUsers to add the new user to the database
DBUsers.add_user(username)
#Click follow
webdriver.find_element_by_xpath('/html/body/div[3]/div[2]/div/article/header/div[2]/div[1]/div[2]/button').click()
followed += 1
print("Followed: {0}, #{1}".format(username, followed))
new_followed.append(username)
# Liking the picture
button_like = webdriver.find_element_by_xpath(
'/html/body/div[3]/div[2]/div/article/div[2]/section[1]/span[1]/button')
button_like.click()
likes += 1
print("Liked {0}'s post, #{1}".format(username, likes))
sleep(random.randint(5, 18))
# Next picture
webdriver.find_element_by_link_text('Next').click()
sleep(random.randint(20, 30))
except:
traceback.print_exc()
continue
t_end = datetime.datetime.now()
#calculate elapsed time
t_elapsed = t_end - t_start
print("This post took {0} seconds".format(t_elapsed.total_seconds()))
except:
traceback.print_exc()
continue
#add new list to old list
for n in range(0, len(new_followed)):
prev_user_list.append(new_followed[n])
print('Liked {} photos.'.format(likes))
print('Followed {} new people.'.format(followed))
It’s pretty long, but generally here’s the steps of the algorithm:
For every hashtag in the hashtag constant list:
Now we might as well implement the unfollow method, hopefully the engine will be feeding us the usernames to unfollow in a list:
def unfollow_people(webdriver, people):
#if only one user, append in a list
if not isinstance(people, (list,)):
p = people
people = []
people.append(p)
for user in people:
try:
webdriver.get('https://www.instagram.com/' + user + '/')
sleep(5)
unfollow_xpath = '//*[@id="react-root"]/section/main/div/header/section/div[1]/div[1]/span/span[1]/button'
unfollow_confirm_xpath = '/html/body/div[3]/div/div/div[3]/button[1]'
if webdriver.find_element_by_xpath(unfollow_xpath).text == "Following":
sleep(random.randint(4, 15))
webdriver.find_element_by_xpath(unfollow_xpath).click()
sleep(2)
webdriver.find_element_by_xpath(unfollow_confirm_xpath).click()
sleep(4)
DBUsers.delete_user(user)
except Exception:
traceback.print_exc()
continue
Now we can finally go back and finish the bot by implementing the rest of BotEngine.py:
import AccountAgent, DBUsers
import Constants
import datetime
def init(webdriver):
Constants.init()
AccountAgent.login(webdriver)
def update(webdriver):
#Get start of time to calculate elapsed time later
start = datetime.datetime.now()
#Before the loop, check if should unfollow anyone
_check_follow_list(webdriver)
while True:
#Start following operation
AccountAgent.follow_people(webdriver)
#Get the time at the end
end = datetime.datetime.now()
#How much time has passed?
elapsed = end - start
#If greater than our constant to check on
#followers, check on followers
if elapsed.total_seconds() >= Constants.CHECK_FOLLOWERS_EVERY:
#reset the start variable to now
start = datetime.datetime.now()
#check on followers
_check_follow_list(webdriver)
def _check_follow_list(webdriver):
print("Checking for users to unfollow")
#get the unfollow list
users = DBUsers.check_unfollow_list()
#if there's anyone in the list, start unfollowing operation
if len(users) > 0:
AccountAgent.unfollow_people(webdriver, users)
And that’s it — now you have yourself a fully functional Instagram bot built with Python and Selenium. There are many possibilities for you to explore now, so make sure you’re using this newly gained skill to solve real life problems!
You can get the source code for the whole project from this GitHub repository.
Here we build a simple bot using some simple Python which beginner to intermediate coders can follow.
Here’s the code on GitHub
https://github.com/aj-4/ig-followers
Source Code: https://github.com/jg-fisher/instagram-bot
How to Get Instagram Followers/Likes Using Python
In this video I show you how to program your own Instagram Bot using Python and Selenium.
https://www.youtube.com/watch?v=BGU2X5lrz9M
Code Link:
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import time
import random
import sys
def print_same_line(text):
sys.stdout.write('\r')
sys.stdout.flush()
sys.stdout.write(text)
sys.stdout.flush()
class InstagramBot:
def __init__(self, username, password):
self.username = username
self.password = password
self.driver = webdriver.Chrome()
def closeBrowser(self):
self.driver.close()
def login(self):
driver = self.driver
driver.get("https://www.instagram.com/")
time.sleep(2)
login_button = driver.find_element_by_xpath("//a[@href='/accounts/login/?source=auth_switcher']")
login_button.click()
time.sleep(2)
user_name_elem = driver.find_element_by_xpath("//input[@name='username']")
user_name_elem.clear()
user_name_elem.send_keys(self.username)
passworword_elem = driver.find_element_by_xpath("//input[@name='password']")
passworword_elem.clear()
passworword_elem.send_keys(self.password)
passworword_elem.send_keys(Keys.RETURN)
time.sleep(2)
def like_photo(self, hashtag):
driver = self.driver
driver.get("https://www.instagram.com/explore/tags/" + hashtag + "/")
time.sleep(2)
# gathering photos
pic_hrefs = []
for i in range(1, 7):
try:
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
time.sleep(2)
# get tags
hrefs_in_view = driver.find_elements_by_tag_name('a')
# finding relevant hrefs
hrefs_in_view = [elem.get_attribute('href') for elem in hrefs_in_view
if '.com/p/' in elem.get_attribute('href')]
# building list of unique photos
[pic_hrefs.append(href) for href in hrefs_in_view if href not in pic_hrefs]
# print("Check: pic href length " + str(len(pic_hrefs)))
except Exception:
continue
# Liking photos
unique_photos = len(pic_hrefs)
for pic_href in pic_hrefs:
driver.get(pic_href)
time.sleep(2)
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
try:
time.sleep(random.randint(2, 4))
like_button = lambda: driver.find_element_by_xpath('//span[@aria-label="Like"]').click()
like_button().click()
for second in reversed(range(0, random.randint(18, 28))):
print_same_line("#" + hashtag + ': unique photos left: ' + str(unique_photos)
+ " | Sleeping " + str(second))
time.sleep(1)
except Exception as e:
time.sleep(2)
unique_photos -= 1
if __name__ == "__main__":
username = "USERNAME"
password = "PASSWORD"
ig = InstagramBot(username, password)
ig.login()
hashtags = ['amazing', 'beautiful', 'adventure', 'photography', 'nofilter',
'newyork', 'artsy', 'alumni', 'lion', 'best', 'fun', 'happy',
'art', 'funny', 'me', 'followme', 'follow', 'cinematography', 'cinema',
'love', 'instagood', 'instagood', 'followme', 'fashion', 'sun', 'scruffy',
'street', 'canon', 'beauty', 'studio', 'pretty', 'vintage', 'fierce']
while True:
try:
# Choose a random tag from the list of tags
tag = random.choice(hashtags)
ig.like_photo(tag)
except Exception:
ig.closeBrowser()
time.sleep(60)
ig = InstagramBot(username, password)
ig.login()
Build An INSTAGRAM Bot With Python That Gets You Followers
Instagram Automation Using Python
How to Create an Instagram Bot | Get More Followers
Building a simple Instagram Influencer Bot with Python tutorial
#python #chatbot #web-development
1657081614
In this article, We will show how we can use python to automate Excel . A useful Python library is Openpyxl which we will learn to do Excel Automation
Openpyxl is a Python library that is used to read from an Excel file or write to an Excel file. Data scientists use Openpyxl for data analysis, data copying, data mining, drawing charts, styling sheets, adding formulas, and more.
Workbook: A spreadsheet is represented as a workbook in openpyxl. A workbook consists of one or more sheets.
Sheet: A sheet is a single page composed of cells for organizing data.
Cell: The intersection of a row and a column is called a cell. Usually represented by A1, B5, etc.
Row: A row is a horizontal line represented by a number (1,2, etc.).
Column: A column is a vertical line represented by a capital letter (A, B, etc.).
Openpyxl can be installed using the pip command and it is recommended to install it in a virtual environment.
pip install openpyxl
We start by creating a new spreadsheet, which is called a workbook in Openpyxl. We import the workbook module from Openpyxl and use the function Workbook()
which creates a new workbook.
from openpyxl
import Workbook
#creates a new workbook
wb = Workbook()
#Gets the first active worksheet
ws = wb.active
#creating new worksheets by using the create_sheet method
ws1 = wb.create_sheet("sheet1", 0) #inserts at first position
ws2 = wb.create_sheet("sheet2") #inserts at last position
ws3 = wb.create_sheet("sheet3", -1) #inserts at penultimate position
#Renaming the sheet
ws.title = "Example"
#save the workbook
wb.save(filename = "example.xlsx")
We load the file using the function load_Workbook()
which takes the filename as an argument. The file must be saved in the same working directory.
#loading a workbook
wb = openpyxl.load_workbook("example.xlsx")
#getting sheet names
wb.sheetnames
result = ['sheet1', 'Sheet', 'sheet3', 'sheet2']
#getting a particular sheet
sheet1 = wb["sheet2"]
#getting sheet title
sheet1.title
result = 'sheet2'
#Getting the active sheet
sheetactive = wb.active
result = 'sheet1'
#get a cell from the sheet
sheet1["A1"] <
Cell 'Sheet1'.A1 >
#get the cell value
ws["A1"].value 'Segment'
#accessing cell using row and column and assigning a value
d = ws.cell(row = 4, column = 2, value = 10)
d.value
10
#looping through each row and column
for x in range(1, 5):
for y in range(1, 5):
print(x, y, ws.cell(row = x, column = y)
.value)
#getting the highest row number
ws.max_row
701
#getting the highest column number
ws.max_column
19
There are two functions for iterating through rows and columns.
Iter_rows() => returns the rows
Iter_cols() => returns the columns {
min_row = 4, max_row = 5, min_col = 2, max_col = 5
} => This can be used to set the boundaries
for any iteration.
Example:
#iterating rows
for row in ws.iter_rows(min_row = 2, max_col = 3, max_row = 3):
for cell in row:
print(cell) <
Cell 'Sheet1'.A2 >
<
Cell 'Sheet1'.B2 >
<
Cell 'Sheet1'.C2 >
<
Cell 'Sheet1'.A3 >
<
Cell 'Sheet1'.B3 >
<
Cell 'Sheet1'.C3 >
#iterating columns
for col in ws.iter_cols(min_row = 2, max_col = 3, max_row = 3):
for cell in col:
print(cell) <
Cell 'Sheet1'.A2 >
<
Cell 'Sheet1'.A3 >
<
Cell 'Sheet1'.B2 >
<
Cell 'Sheet1'.B3 >
<
Cell 'Sheet1'.C2 >
<
Cell 'Sheet1'.C3 >
To get all the rows of the worksheet we use the method worksheet.rows and to get all the columns of the worksheet we use the method worksheet.columns. Similarly, to iterate only through the values we use the method worksheet.values.
Example:
for row in ws.values:
for value in row:
print(value)
Writing to a workbook can be done in many ways such as adding a formula, adding charts, images, updating cell values, inserting rows and columns, etc… We will discuss each of these with an example.
#creates a new workbook
wb = openpyxl.Workbook()
#saving the workbook
wb.save("new.xlsx")
#creating a new sheet
ws1 = wb.create_sheet(title = "sheet 2")
#creating a new sheet at index 0
ws2 = wb.create_sheet(index = 0, title = "sheet 0")
#checking the sheet names
wb.sheetnames['sheet 0', 'Sheet', 'sheet 2']
#deleting a sheet
del wb['sheet 0']
#checking sheetnames
wb.sheetnames['Sheet', 'sheet 2']
#checking the sheet value
ws['B2'].value
null
#adding value to cell
ws['B2'] = 367
#checking value
ws['B2'].value
367
We often require formulas to be included in our Excel datasheet. We can easily add formulas using the Openpyxl module just like you add values to a cell.
For example:
import openpyxl
from openpyxl
import Workbook
wb = openpyxl.load_workbook("new1.xlsx")
ws = wb['Sheet']
ws['A9'] = '=SUM(A2:A8)'
wb.save("new2.xlsx")
The above program will add the formula (=SUM(A2:A8)) in cell A9. The result will be as below.
Two or more cells can be merged to a rectangular area using the method merge_cells(), and similarly, they can be unmerged using the method unmerge_cells().
For example:
Merge cells
#merge cells B2 to C9
ws.merge_cells('B2:C9')
ws['B2'] = "Merged cells"
Adding the above code to the previous example will merge cells as below.
#unmerge cells B2 to C9
ws.unmerge_cells('B2:C9')
The above code will unmerge cells from B2 to C9.
To insert an image we import the image function from the module openpyxl.drawing.image. We then load our image and add it to the cell as shown in the below example.
Example:
import openpyxl
from openpyxl
import Workbook
from openpyxl.drawing.image
import Image
wb = openpyxl.load_workbook("new1.xlsx")
ws = wb['Sheet']
#loading the image(should be in same folder)
img = Image('logo.png')
ws['A1'] = "Adding image"
#adjusting size
img.height = 130
img.width = 200
#adding img to cell A3
ws.add_image(img, 'A3')
wb.save("new2.xlsx")
Result:
Charts are essential to show a visualization of data. We can create charts from Excel data using the Openpyxl module chart. Different forms of charts such as line charts, bar charts, 3D line charts, etc., can be created. We need to create a reference that contains the data to be used for the chart, which is nothing but a selection of cells (rows and columns). I am using sample data to create a 3D bar chart in the below example:
Example
import openpyxl
from openpyxl
import Workbook
from openpyxl.chart
import BarChart3D, Reference, series
wb = openpyxl.load_workbook("example.xlsx")
ws = wb.active
values = Reference(ws, min_col = 3, min_row = 2, max_col = 3, max_row = 40)
chart = BarChart3D()
chart.add_data(values)
ws.add_chart(chart, "E3")
wb.save("MyChart.xlsx")
Result
Welcome to another video! In this video, We will cover how we can use python to automate Excel. I'll be going over everything from creating workbooks to accessing individual cells and stylizing cells. There is a ton of things that you can do with Excel but I'll just be covering the core/base things in OpenPyXl.
⭐️ Timestamps ⭐️
00:00 | Introduction
02:14 | Installing openpyxl
03:19 | Testing Installation
04:25 | Loading an Existing Workbook
06:46 | Accessing Worksheets
07:37 | Accessing Cell Values
08:58 | Saving Workbooks
09:52 | Creating, Listing and Changing Sheets
11:50 | Creating a New Workbook
12:39 | Adding/Appending Rows
14:26 | Accessing Multiple Cells
20:46 | Merging Cells
22:27 | Inserting and Deleting Rows
23:35 | Inserting and Deleting Columns
24:48 | Copying and Moving Cells
26:06 | Practical Example, Formulas & Cell Styling
📄 Resources 📄
OpenPyXL Docs: https://openpyxl.readthedocs.io/en/stable/
Code Written in This Tutorial: https://github.com/techwithtim/ExcelPythonTutorial
Subscribe: https://www.youtube.com/c/TechWithTim/featured
1614329473
G Suite is one of the Google products, developed form of Google Apps. It is a single platform to hold cloud computing, collaboration tools, productivity, software, and products. While using it, many a time, it’s not working, and users have a question– How to fix G Suite not working on iPhone? It can be resolved easily by restarting the device, and if unable to do so, you can reach our specialists whenever you want.
For more details: https://contactforhelp.com/blog/how-to-fix-the-g-suite-email-not-working-issue/
#g suite email not working #g suite email not working on iphone #g suite email not working on android #suite email not working on windows 10 #g suite email not working on mac #g suite email not syncing
1644477426
Minimal and clean example implementations of data structures and algorithms in Python 3.
For running all tests write down:
$ python3 -m unittest discover tests
For running some specific tests you can do this as following (Ex: sort):
$ python3 -m unittest tests.test_sort
For running all tests write down:
$ python3 -m pytest tests
If you want to use the API algorithms in your code, it is as simple as:
$ pip3 install algorithms
You can test by creating a python file: (Ex: use merge_sort
in sort
)
from algorithms.sort import merge_sort
if __name__ == "__main__":
my_list = [1, 8, 3, 5, 6]
my_list = merge_sort(my_list)
print(my_list)
If you want to uninstall algorithms, it is as simple as:
$ pip3 uninstall -y algorithms
"""
Given a list lst and a number N, create a new list
that contains each number of the list at most N times without reordering.
For example if N = 2, and the input is [1,2,3,1,2,1,2,3], you take [1,2,3,1,2],
drop the next [1,2] since this would lead to 1 and 2 being in the result 3 times, and then take 3,
which leads to [1,2,3,1,2,3]
"""
import collections
# Time complexity O(n^2)
def delete_nth_naive(array, n):
ans = []
for num in array:
if ans.count(num) < n:
ans.append(num)
return ans
# Time Complexity O(n), using hash tables.
def delete_nth(array, n):
result = []
counts = collections.defaultdict(int) # keep track of occurrences
for i in array:
if counts[i] < n:
result.append(i)
counts[i] += 1
return result
"""
Implement Flatten Arrays.
Given an array that may contain nested arrays,
produce a single resultant array.
"""
from collections.abc import Iterable
# return list
def flatten(input_arr, output_arr=None):
if output_arr is None:
output_arr = []
for ele in input_arr:
if not isinstance(ele, str) and isinstance(ele, Iterable):
flatten(ele, output_arr) #tail-recursion
else:
output_arr.append(ele) #produce the result
return output_arr
# returns iterator
def flatten_iter(iterable):
"""
Takes as input multi dimensional iterable and
returns generator which produces one dimensional output.
"""
for element in iterable:
if not isinstance(element, str) and isinstance(element, Iterable):
yield from flatten_iter(element)
else:
yield element
"""
There is a parking lot with only one empty spot. Given the initial state
of the parking lot and the final state. Each step we are only allowed to
move a car
out of its place and move it into the empty spot.
The goal is to find out the least movement needed to rearrange
the parking lot from the initial state to the final state.
Say the initial state is an array:
[1, 2, 3, 0, 4],
where 1, 2, 3, 4 are different cars, and 0 is the empty spot.
And the final state is
[0, 3, 2, 1, 4].
We can swap 1 with 0 in the initial array to get [0, 2, 3, 1, 4] and so on.
Each step swap with 0 only.
Edit:
Now also prints the sequence of changes in states.
Output of this example :-
initial: [1, 2, 3, 0, 4]
final: [0, 3, 2, 1, 4]
Steps = 4
Sequence :
0 2 3 1 4
2 0 3 1 4
2 3 0 1 4
0 3 2 1 4
"""
def garage(initial, final):
initial = initial[::] # prevent changes in original 'initial'
seq = [] # list of each step in sequence
steps = 0
while initial != final:
zero = initial.index(0)
if zero != final.index(0): # if zero isn't where it should be,
car_to_move = final[zero] # what should be where zero is,
pos = initial.index(car_to_move) # and where is it?
initial[zero], initial[pos] = initial[pos], initial[zero]
else:
for i in range(len(initial)):
if initial[i] != final[i]:
initial[zero], initial[i] = initial[i], initial[zero]
break
seq.append(initial[::])
steps += 1
return steps, seq
# e.g.: 4, [{0, 2, 3, 1, 4}, {2, 0, 3, 1, 4},
# {2, 3, 0, 1, 4}, {0, 3, 2, 1, 4}]
"""
thus:
1 2 3 0 4 -- zero = 3, true, car_to_move = final[3] = 1,
pos = initial.index(1) = 0, switched [0], [3]
0 2 3 1 4 -- zero = 0, f, initial[1] != final[1], switched 0,1
2 0 3 1 4 -- zero = 1, t, car_to_move = final[1] = 3,
pos = initial.index(3) = 2, switched [1], [2]
2 3 0 1 4 -- zero = 2, t, car_to_move = final[2] = 2,
pos = initial.index(2) = 0, switched [0], [2]
0 3 2 1 4 -- initial == final
"""
"""
There are people sitting in a circular fashion,
print every third member while removing them,
the next counter starts immediately after the member is removed.
Print till all the members are exhausted.
For example:
Input: consider 123456789 members sitting in a circular fashion,
Output: 369485271
"""
def josephus(int_list, skip):
skip = skip - 1 # list starts with 0 index
idx = 0
len_list = (len(int_list))
while len_list > 0:
idx = (skip + idx) % len_list # hash index to every 3rd
yield int_list.pop(idx)
len_list -= 1
"""
Sometimes you need to limit array result to use. Such as you only need the
value over 10 or, you need value under than 100. By use this algorithms, you
can limit your array to specific value
If array, Min, Max value was given, it returns array that contains values of
given array which was larger than Min, and lower than Max. You need to give
'unlimit' to use only Min or Max.
ex) limit([1,2,3,4,5], None, 3) = [1,2,3]
Complexity = O(n)
"""
# tl:dr -- array slicing by value
def limit(arr, min_lim=None, max_lim=None):
return list(filter(lambda x: (min_lim <= x <= max_lim), arr))
"""
Given a string, find the length of the longest substring
without repeating characters.
Examples:
Given "abcabcbb", the answer is "abc", which the length is 3.
Given "bbbbb", the answer is "b", with the length of 1.
Given "pwwkew", the answer is "wke", with the length of 3.
Note that the answer must be a substring,
"pwke" is a subsequence and not a substring.
"""
def longest_non_repeat_v1(string):
"""
Find the length of the longest substring
without repeating characters.
"""
if string is None:
return 0
dict = {}
max_length = 0
j = 0
for i in range(len(string)):
if string[i] in dict:
j = max(dict[string[i]], j)
dict[string[i]] = i + 1
max_length = max(max_length, i - j + 1)
return max_length
def longest_non_repeat_v2(string):
"""
Find the length of the longest substring
without repeating characters.
Uses alternative algorithm.
"""
if string is None:
return 0
start, max_len = 0, 0
used_char = {}
for index, char in enumerate(string):
if char in used_char and start <= used_char[char]:
start = used_char[char] + 1
else:
max_len = max(max_len, index - start + 1)
used_char[char] = index
return max_len
# get functions of above, returning the max_len and substring
def get_longest_non_repeat_v1(string):
"""
Find the length of the longest substring
without repeating characters.
Return max_len and the substring as a tuple
"""
if string is None:
return 0, ''
sub_string = ''
dict = {}
max_length = 0
j = 0
for i in range(len(string)):
if string[i] in dict:
j = max(dict[string[i]], j)
dict[string[i]] = i + 1
if i - j + 1 > max_length:
max_length = i - j + 1
sub_string = string[j: i + 1]
return max_length, sub_string
def get_longest_non_repeat_v2(string):
"""
Find the length of the longest substring
without repeating characters.
Uses alternative algorithm.
Return max_len and the substring as a tuple
"""
if string is None:
return 0, ''
sub_string = ''
start, max_len = 0, 0
used_char = {}
for index, char in enumerate(string):
if char in used_char and start <= used_char[char]:
start = used_char[char] + 1
else:
if index - start + 1 > max_len:
max_len = index - start + 1
sub_string = string[start: index + 1]
used_char[char] = index
return max_len, sub_string
"""
Find the index of 0 to be replaced with 1 to get
longest continuous sequence
of 1s in a binary array.
Returns index of 0 to be
replaced with 1 to get longest
continuous sequence of 1s.
If there is no 0 in array, then
it returns -1.
e.g.
let input array = [1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1]
If we replace 0 at index 3 with 1, we get the longest continuous
sequence of 1s in the array.
So the function return => 3
"""
def max_ones_index(arr):
n = len(arr)
max_count = 0
max_index = 0
prev_zero = -1
prev_prev_zero = -1
for curr in range(n):
# If current element is 0,
# then calculate the difference
# between curr and prev_prev_zero
if arr[curr] == 0:
if curr - prev_prev_zero > max_count:
max_count = curr - prev_prev_zero
max_index = prev_zero
prev_prev_zero = prev_zero
prev_zero = curr
if n - prev_prev_zero > max_count:
max_index = prev_zero
return max_index
"""
In mathematics, a (real) interval is a set of real
numbers with the property that any number that lies
between two numbers in the set is also included in the set.
"""
class Interval:
"""
A set of real numbers with methods to determine if other
numbers are included in the set.
Includes related methods to merge and print interval sets.
"""
def __init__(self, start=0, end=0):
self.start = start
self.end = end
def __repr__(self):
return "Interval ({}, {})".format(self.start, self.end)
def __iter__(self):
return iter(range(self.start, self.end))
def __getitem__(self, index):
if index < 0:
return self.end + index
return self.start + index
def __len__(self):
return self.end - self.start
def __contains__(self, item):
if self.start >= item >= self.end:
return True
return False
def __eq__(self, other):
if self.start == other.start and self.end == other.end:
return True
return False
def as_list(self):
""" Return interval as list. """
return list(self)
@staticmethod
def merge(intervals):
""" Merge two intervals into one. """
out = []
for i in sorted(intervals, key=lambda i: i.start):
if out and i.start <= out[-1].end:
out[-1].end = max(out[-1].end, i.end)
else:
out += i,
return out
@staticmethod
def print_intervals(intervals):
""" Print out the intervals. """
res = []
for i in intervals:
res.append(repr(i))
print("".join(res))
def merge_intervals(intervals):
""" Merge intervals in the form of a list. """
if intervals is None:
return None
intervals.sort(key=lambda i: i[0])
out = [intervals.pop(0)]
for i in intervals:
if out[-1][-1] >= i[0]:
out[-1][-1] = max(out[-1][-1], i[-1])
else:
out.append(i)
return out
"""
Find missing ranges between low and high in the given array.
Ex) [3, 5] lo=1 hi=10 => answer: [(1, 2), (4, 4), (6, 10)]
"""
def missing_ranges(arr, lo, hi):
res = []
start = lo
for n in arr:
if n == start:
start += 1
elif n > start:
res.append((start, n-1))
start = n + 1
if start <= hi: # after done iterating thru array,
res.append((start, hi)) # append remainder to list
return res
"""
Given a non-negative number represented as an array of digits,
adding one to each numeral.
The digits are stored big-endian, such that the most significant
digit is at the head of the list.
"""
def plus_one_v1(digits):
"""
:type digits: List[int]
:rtype: List[int]
"""
digits[-1] = digits[-1] + 1
res = []
ten = 0
i = len(digits)-1
while i >= 0 or ten == 1:
summ = 0
if i >= 0:
summ += digits[i]
if ten:
summ += 1
res.append(summ % 10)
ten = summ // 10
i -= 1
return res[::-1]
def plus_one_v2(digits):
n = len(digits)
for i in range(n-1, -1, -1):
if digits[i] < 9:
digits[i] += 1
return digits
digits[i] = 0
digits.insert(0, 1)
return digits
def plus_one_v3(num_arr):
for idx in reversed(list(enumerate(num_arr))):
num_arr[idx[0]] = (num_arr[idx[0]] + 1) % 10
if num_arr[idx[0]]:
return num_arr
return [1] + num_arr
"""
Rotate an array of n elements to the right by k steps.
For example, with n = 7 and k = 3,
the array [1,2,3,4,5,6,7] is rotated to [5,6,7,1,2,3,4].
Note:
Try to come up as many solutions as you can,
there are at least 3 different ways to solve this problem.
"""
def rotate_v1(array, k):
"""
Rotate the entire array 'k' times
T(n)- O(nk)
:type array: List[int]
:type k: int
:rtype: void Do not return anything, modify array in-place instead.
"""
array = array[:]
n = len(array)
for i in range(k): # unused variable is not a problem
temp = array[n - 1]
for j in range(n-1, 0, -1):
array[j] = array[j - 1]
array[0] = temp
return array
def rotate_v2(array, k):
"""
Reverse segments of the array, followed by the entire array
T(n)- O(n)
:type array: List[int]
:type k: int
:rtype: void Do not return anything, modify nums in-place instead.
"""
array = array[:]
def reverse(arr, a, b):
while a < b:
arr[a], arr[b] = arr[b], arr[a]
a += 1
b -= 1
n = len(array)
k = k % n
reverse(array, 0, n - k - 1)
reverse(array, n - k, n - 1)
reverse(array, 0, n - 1)
return array
def rotate_v3(array, k):
if array is None:
return None
length = len(array)
k = k % length
return array[length - k:] + array[:length - k]
"""
Given a sorted integer array without duplicates,
return the summary of its ranges.
For example, given [0, 1, 2, 4, 5, 7], return [(0, 2), (4, 5), (7, 7)].
"""
def summarize_ranges(array):
"""
:type array: List[int]
:rtype: List[]
"""
res = []
if len(array) == 1:
return [str(array[0])]
i = 0
while i < len(array):
num = array[i]
while i + 1 < len(array) and array[i + 1] - array[i] == 1:
i += 1
if array[i] != num:
res.append((num, array[i]))
else:
res.append((num, num))
i += 1
return res
"""
Given an array S of n integers, are there three distinct elements
a, b, c in S such that a + b + c = 0?
Find all unique triplets in the array which gives the sum of zero.
Note: The solution set must not contain duplicate triplets.
For example, given array S = [-1, 0, 1, 2, -1, -4],
A solution set is:
{
(-1, 0, 1),
(-1, -1, 2)
}
"""
def three_sum(array):
"""
:param array: List[int]
:return: Set[ Tuple[int, int, int] ]
"""
res = set()
array.sort()
for i in range(len(array) - 2):
if i > 0 and array[i] == array[i - 1]:
continue
l, r = i + 1, len(array) - 1
while l < r:
s = array[i] + array[l] + array[r]
if s > 0:
r -= 1
elif s < 0:
l += 1
else:
# found three sum
res.add((array[i], array[l], array[r]))
# remove duplicates
while l < r and array[l] == array[l + 1]:
l += 1
while l < r and array[r] == array[r - 1]:
r -= 1
l += 1
r -= 1
return res
"""
When make reliable means, we need to neglect best and worst values.
For example, when making average score on athletes we need this option.
So, this algorithm affixes some percentage to neglect when making mean.
For example, if you suggest 20%, it will neglect the best 10% of values
and the worst 10% of values.
This algorithm takes an array and percentage to neglect. After sorted,
if index of array is larger or smaller than desired ratio, we don't
compute it.
Compleity: O(n)
"""
def trimmean(arr, per):
ratio = per/200
# /100 for easy calculation by *, and /2 for easy adaption to best and worst parts.
cal_sum = 0
# sum value to be calculated to trimmean.
arr.sort()
neg_val = int(len(arr)*ratio)
arr = arr[neg_val:len(arr)-neg_val]
for i in arr:
cal_sum += i
return cal_sum/len(arr)
"""
This algorithm receives an array and returns most_frequent_value
Also, sometimes it is possible to have multiple 'most_frequent_value's,
so this function returns a list. This result can be used to find a
representative value in an array.
This algorithm gets an array, makes a dictionary of it,
finds the most frequent count, and makes the result list.
For example: top_1([1, 1, 2, 2, 3, 4]) will return [1, 2]
(TL:DR) Get mathematical Mode
Complexity: O(n)
"""
def top_1(arr):
values = {}
#reserve each value which first appears on keys
#reserve how many time each value appears by index number on values
result = []
f_val = 0
for i in arr:
if i in values:
values[i] += 1
else:
values[i] = 1
f_val = max(values.values())
for i in values.keys():
if values[i] == f_val:
result.append(i)
else:
continue
return result
"""
Given an array of integers, return indices of the two numbers
such that they add up to a specific target.
You may assume that each input would have exactly one solution,
and you may not use the same element twice.
Example:
Given nums = [2, 7, 11, 15], target = 9,
Because nums[0] + nums[1] = 2 + 7 = 9,
return (0, 1)
"""
def two_sum(array, target):
dic = {}
for i, num in enumerate(array):
if num in dic:
return dic[num], i
else:
dic[target - num] = i
return None
"""
Write an algorithm that takes an array and moves all of the zeros to the end,
preserving the order of the other elements.
move_zeros([false, 1, 0, 1, 2, 0, 1, 3, "a"])
returns => [false, 1, 1, 2, 1, 3, "a", 0, 0]
The time complexity of the below algorithm is O(n).
"""
# False == 0 is True
def move_zeros(array):
result = []
zeros = 0
for i in array:
if i == 0 and type(i) != bool: # not using `not i` to avoid `False`, `[]`, etc.
zeros += 1
else:
result.append(i)
result.extend([0] * zeros)
return result
print(move_zeros([False, 1, 0, 1, 2, 0, 1, 3, "a"]))
"""
Given an array of n integers, are there elements a, b, .. , n in nums
such that a + b + .. + n = target?
Find all unique n-tuplets in the array which gives the sum of target.
Example:
basic:
Given:
n = 4
nums = [1, 0, -1, 0, -2, 2]
target = 0,
return [[-2, -1, 1, 2], [-2, 0, 0, 2], [-1, 0, 0, 1]]
advanced:
Given:
n = 2
nums = [[-3, 0], [-2, 1], [2, 2], [3, 3], [8, 4], [-9, 5]]
target = -5
def sum(a, b):
return [a[0] + b[1], a[1] + b[0]]
def compare(num, target):
if num[0] < target:
return -1
elif if num[0] > target:
return 1
else:
return 0
return [[-9, 5], [8, 4]]
(TL:DR) because -9 + 4 = -5
"""
def n_sum(n, nums, target, **kv):
"""
n: int
nums: list[object]
target: object
sum_closure: function, optional
Given two elements of nums, return sum of both.
compare_closure: function, optional
Given one object of nums and target, return -1, 1, or 0.
same_closure: function, optional
Given two object of nums, return bool.
return: list[list[object]]
Note:
1. type of sum_closure's return should be same
as type of compare_closure's first param
"""
def sum_closure_default(a, b):
return a + b
def compare_closure_default(num, target):
""" above, below, or right on? """
if num < target:
return -1
elif num > target:
return 1
else:
return 0
def same_closure_default(a, b):
return a == b
def n_sum(n, nums, target):
if n == 2: # want answers with only 2 terms? easy!
results = two_sum(nums, target)
else:
results = []
prev_num = None
for index, num in enumerate(nums):
if prev_num is not None and \
same_closure(prev_num, num):
continue
prev_num = num
n_minus1_results = (
n_sum( # recursive call
n - 1, # a
nums[index + 1:], # b
target - num # c
) # x = n_sum( a, b, c )
) # n_minus1_results = x
n_minus1_results = (
append_elem_to_each_list(num, n_minus1_results)
)
results += n_minus1_results
return union(results)
def two_sum(nums, target):
nums.sort()
lt = 0
rt = len(nums) - 1
results = []
while lt < rt:
sum_ = sum_closure(nums[lt], nums[rt])
flag = compare_closure(sum_, target)
if flag == -1:
lt += 1
elif flag == 1:
rt -= 1
else:
results.append(sorted([nums[lt], nums[rt]]))
lt += 1
rt -= 1
while (lt < len(nums) and
same_closure(nums[lt - 1], nums[lt])):
lt += 1
while (0 <= rt and
same_closure(nums[rt], nums[rt + 1])):
rt -= 1
return results
def append_elem_to_each_list(elem, container):
results = []
for elems in container:
elems.append(elem)
results.append(sorted(elems))
return results
def union(duplicate_results):
results = []
if len(duplicate_results) != 0:
duplicate_results.sort()
results.append(duplicate_results[0])
for result in duplicate_results[1:]:
if results[-1] != result:
results.append(result)
return results
sum_closure = kv.get('sum_closure', sum_closure_default)
same_closure = kv.get('same_closure', same_closure_default)
compare_closure = kv.get('compare_closure', compare_closure_default)
nums.sort()
return n_sum(n, nums, target)
def DFA(transitions, start, final, string):
num = len(string)
num_final = len(final)
cur = start
for i in range(num):
if transitions[cur][string[i]] is None:
return False
else:
cur = transitions[cur][string[i]]
for i in range(num_final):
if cur == final[i]:
return True
return False
"""
Given a string that contains only digits 0-9 and a target value,
return all possibilities to add binary operators (not unary) +, -, or *
between the digits so they prevuate to the target value.
Examples:
"123", 6 -> ["1+2+3", "1*2*3"]
"232", 8 -> ["2*3+2", "2+3*2"]
"105", 5 -> ["1*0+5","10-5"]
"00", 0 -> ["0+0", "0-0", "0*0"]
"3456237490", 9191 -> []
"""
def add_operators(num, target):
"""
:type num: str
:type target: int
:rtype: List[str]
"""
def dfs(res, path, num, target, pos, prev, multed):
if pos == len(num):
if target == prev:
res.append(path)
return
for i in range(pos, len(num)):
if i != pos and num[pos] == '0': # all digits have to be used
break
cur = int(num[pos:i+1])
if pos == 0:
dfs(res, path + str(cur), num, target, i+1, cur, cur)
else:
dfs(res, path + "+" + str(cur), num, target,
i+1, prev + cur, cur)
dfs(res, path + "-" + str(cur), num, target,
i+1, prev - cur, -cur)
dfs(res, path + "*" + str(cur), num, target,
i+1, prev - multed + multed * cur, multed * cur)
res = []
if not num:
return res
dfs(res, "", num, target, 0, 0, 0)
return res
"""
Given two strings, determine if they are equal after reordering.
Examples:
"apple", "pleap" -> True
"apple", "cherry" -> False
"""
def anagram(s1, s2):
c1 = [0] * 26
c2 = [0] * 26
for c in s1:
pos = ord(c)-ord('a')
c1[pos] = c1[pos] + 1
for c in s2:
pos = ord(c)-ord('a')
c2[pos] = c2[pos] + 1
return c1 == c2
"""
WAP to take one element from each of the array add it to the target sum.
Print all those three-element combinations.
/*
A = [1, 2, 3, 3]
B = [2, 3, 3, 4]
C = [2, 3, 3, 4]
target = 7
*/
Result:
[[1, 2, 4], [1, 3, 3], [1, 3, 3], [1, 3, 3], [1, 3, 3], [1, 4, 2],
[2, 2, 3], [2, 2, 3], [2, 3, 2], [2, 3, 2], [3, 2, 2], [3, 2, 2]]
"""
import itertools
from functools import partial
def array_sum_combinations(A, B, C, target):
def over(constructed_sofar):
sum = 0
to_stop, reached_target = False, False
for elem in constructed_sofar:
sum += elem
if sum >= target or len(constructed_sofar) >= 3:
to_stop = True
if sum == target and 3 == len(constructed_sofar):
reached_target = True
return to_stop, reached_target
def construct_candidates(constructed_sofar):
array = A
if 1 == len(constructed_sofar):
array = B
elif 2 == len(constructed_sofar):
array = C
return array
def backtrack(constructed_sofar=[], res=[]):
to_stop, reached_target = over(constructed_sofar)
if to_stop:
if reached_target:
res.append(constructed_sofar)
return
candidates = construct_candidates(constructed_sofar)
for candidate in candidates:
constructed_sofar.append(candidate)
backtrack(constructed_sofar[:], res)
constructed_sofar.pop()
res = []
backtrack([], res)
return res
def unique_array_sum_combinations(A, B, C, target):
"""
1. Sort all the arrays - a,b,c. - This improves average time complexity.
2. If c[i] < Sum, then look for Sum - c[i] in array a and b.
When pair found, insert c[i], a[j] & b[k] into the result list.
This can be done in O(n).
3. Keep on doing the above procedure while going through complete c array.
Complexity: O(n(m+p))
"""
def check_sum(n, *nums):
if sum(x for x in nums) == n:
return (True, nums)
else:
return (False, nums)
pro = itertools.product(A, B, C)
func = partial(check_sum, target)
sums = list(itertools.starmap(func, pro))
res = set()
for s in sums:
if s[0] is True and s[1] not in res:
res.add(s[1])
return list(res)
"""
Given a set of candidate numbers (C) (without duplicates) and a target number
(T), find all unique combinations in C where the candidate numbers sums to T.
The same repeated number may be chosen from C unlimited number of times.
Note:
All numbers (including target) will be positive integers.
The solution set must not contain duplicate combinations.
For example, given candidate set [2, 3, 6, 7] and target 7,
A solution set is:
[
[7],
[2, 2, 3]
]
"""
def combination_sum(candidates, target):
def dfs(nums, target, index, path, res):
if target < 0:
return # backtracking
if target == 0:
res.append(path)
return
for i in range(index, len(nums)):
dfs(nums, target-nums[i], i, path+[nums[i]], res)
res = []
candidates.sort()
dfs(candidates, target, 0, [], res)
return res
"""
Numbers can be regarded as product of its factors. For example,
8 = 2 x 2 x 2;
= 2 x 4.
Write a function that takes an integer n
and return all possible combinations of its factors.
Note:
You may assume that n is always positive.
Factors should be greater than 1 and less than n.
Examples:
input: 1
output:
[]
input: 37
output:
[]
input: 12
output:
[
[2, 6],
[2, 2, 3],
[3, 4]
]
input: 32
output:
[
[2, 16],
[2, 2, 8],
[2, 2, 2, 4],
[2, 2, 2, 2, 2],
[2, 4, 4],
[4, 8]
]
"""
# Iterative:
def get_factors(n):
todo, combis = [(n, 2, [])], []
while todo:
n, i, combi = todo.pop()
while i * i <= n:
if n % i == 0:
combis.append(combi + [i, n//i])
todo.append((n//i, i, combi+[i]))
i += 1
return combis
# Recursive:
def recursive_get_factors(n):
def factor(n, i, combi, combis):
while i * i <= n:
if n % i == 0:
combis.append(combi + [i, n//i]),
factor(n//i, i, combi+[i], combis)
i += 1
return combis
return factor(n, 2, [], [])
"""
given input word, return the list of abbreviations.
ex)
word => ['word', 'wor1', 'wo1d', 'wo2', 'w1rd', 'w1r1', 'w2d', 'w3', '1ord', '1or1', '1o1d', '1o2', '2rd', '2r1', '3d', '4']
"""
def generate_abbreviations(word):
def backtrack(result, word, pos, count, cur):
if pos == len(word):
if count > 0:
cur += str(count)
result.append(cur)
return
if count > 0: # add the current word
backtrack(result, word, pos+1, 0, cur+str(count)+word[pos])
else:
backtrack(result, word, pos+1, 0, cur+word[pos])
# skip the current word
backtrack(result, word, pos+1, count+1, cur)
result = []
backtrack(result, word, 0, 0, "")
return result
"""
Given n pairs of parentheses, write a function to generate
all combinations of well-formed parentheses.
For example, given n = 3, a solution set is:
[
"((()))",
"(()())",
"(())()",
"()(())",
"()()()"
]
"""
def generate_parenthesis_v1(n):
def add_pair(res, s, left, right):
if left == 0 and right == 0:
res.append(s)
return
if right > 0:
add_pair(res, s + ")", left, right - 1)
if left > 0:
add_pair(res, s + "(", left - 1, right + 1)
res = []
add_pair(res, "", n, 0)
return res
def generate_parenthesis_v2(n):
def add_pair(res, s, left, right):
if left == 0 and right == 0:
res.append(s)
if left > 0:
add_pair(res, s + "(", left - 1, right)
if right > 0 and left < right:
add_pair(res, s + ")", left, right - 1)
res = []
add_pair(res, "", n, n)
return res
"""
Given a digit string, return all possible letter
combinations that the number could represent.
A mapping of digit to letters (just like on the telephone buttons) is given below:
2: "abc"
3: "def"
4: "ghi"
5: "jkl"
6: "mno"
7: "pqrs"
8: "tuv"
9: "wxyz"
Input:Digit string "23"
Output: ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"].
"""
def letter_combinations(digits):
if digits == "":
return []
kmaps = {
"2": "abc",
"3": "def",
"4": "ghi",
"5": "jkl",
"6": "mno",
"7": "pqrs",
"8": "tuv",
"9": "wxyz"
}
ans = [""]
for num in digits:
tmp = []
for an in ans:
for char in kmaps[num]:
tmp.append(an + char)
ans = tmp
return ans
""" It looks like you need to be looking not for all palindromic substrings,
but rather for all the ways you can divide the input string
up into palindromic substrings.
(There's always at least one way,
since one-character substrings are always palindromes.)
ex)
'abcbab' => [['abcba', 'b'], ['a', 'bcb', 'a', 'b'], ['a', 'b', 'c', 'bab'], ['a', 'b', 'c', 'b', 'a', 'b']]
"""
def palindromic_substrings(s):
if not s:
return [[]]
results = []
for i in range(len(s), 0, -1):
sub = s[:i]
if sub == sub[::-1]:
for rest in palindromic_substrings(s[i:]):
results.append([sub] + rest)
return results
"""
There's two loops.
The outer loop checks each length of initial substring
(in descending length order) to see if it is a palindrome.
If so, it recurses on the rest of the string and loops over the returned
values, adding the initial substring to
each item before adding it to the results.
"""
def palindromic_substrings_iter(s):
"""
A slightly more Pythonic approach with a recursive generator
"""
if not s:
yield []
return
for i in range(len(s), 0, -1):
sub = s[:i]
if sub == sub[::-1]:
for rest in palindromic_substrings_iter(s[i:]):
yield [sub] + rest
"""
Given a pattern and a string str,
find if str follows the same pattern.
Here follow means a full match, such that there is a bijection between
a letter in pattern and a non-empty substring in str.
Examples:
pattern = "abab", str = "redblueredblue" should return true.
pattern = "aaaa", str = "asdasdasdasd" should return true.
pattern = "aabb", str = "xyzabcxzyabc" should return false.
Notes:
You may assume both pattern and str contains only lowercase letters.
"""
def pattern_match(pattern, string):
"""
:type pattern: str
:type string: str
:rtype: bool
"""
def backtrack(pattern, string, dic):
if len(pattern) == 0 and len(string) > 0:
return False
if len(pattern) == len(string) == 0:
return True
for end in range(1, len(string)-len(pattern)+2):
if pattern[0] not in dic and string[:end] not in dic.values():
dic[pattern[0]] = string[:end]
if backtrack(pattern[1:], string[end:], dic):
return True
del dic[pattern[0]]
elif pattern[0] in dic and dic[pattern[0]] == string[:end]:
if backtrack(pattern[1:], string[end:], dic):
return True
return False
return backtrack(pattern, string, {})
"""
Given a collection of distinct numbers, return all possible permutations.
For example,
[1,2,3] have the following permutations:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]
"""
def permute(elements):
"""
returns a list with the permuations.
"""
if len(elements) <= 1:
return [elements]
else:
tmp = []
for perm in permute(elements[1:]):
for i in range(len(elements)):
tmp.append(perm[:i] + elements[0:1] + perm[i:])
return tmp
def permute_iter(elements):
"""
iterator: returns a perumation by each call.
"""
if len(elements) <= 1:
yield elements
else:
for perm in permute_iter(elements[1:]):
for i in range(len(elements)):
yield perm[:i] + elements[0:1] + perm[i:]
# DFS Version
def permute_recursive(nums):
def dfs(res, nums, path):
if not nums:
res.append(path)
for i in range(len(nums)):
print(nums[:i]+nums[i+1:])
dfs(res, nums[:i]+nums[i+1:], path+[nums[i]])
res = []
dfs(res, nums, [])
return res
"""
Given a collection of numbers that might contain duplicates,
return all possible unique permutations.
For example,
[1,1,2] have the following unique permutations:
[
[1,1,2],
[1,2,1],
[2,1,1]
]
"""
def permute_unique(nums):
perms = [[]]
for n in nums:
new_perms = []
for l in perms:
for i in range(len(l)+1):
new_perms.append(l[:i]+[n]+l[i:])
if i < len(l) and l[i] == n:
break # handles duplication
perms = new_perms
return perms
"""
Given a set of distinct integers, nums, return all possible subsets.
Note: The solution set must not contain duplicate subsets.
For example,
If nums = [1,2,3], a solution is:
[
[3],
[1],
[2],
[1,2,3],
[1,3],
[2,3],
[1,2],
[]
]
"""
def subsets(nums):
"""
O(2**n)
"""
def backtrack(res, nums, stack, pos):
if pos == len(nums):
res.append(list(stack))
else:
# take nums[pos]
stack.append(nums[pos])
backtrack(res, nums, stack, pos+1)
stack.pop()
# dont take nums[pos]
backtrack(res, nums, stack, pos+1)
res = []
backtrack(res, nums, [], 0)
return res
"""
simplified backtrack
def backtrack(res, nums, cur, pos):
if pos >= len(nums):
res.append(cur)
else:
backtrack(res, nums, cur+[nums[pos]], pos+1)
backtrack(res, nums, cur, pos+1)
"""
# Iteratively
def subsets_v2(nums):
res = [[]]
for num in sorted(nums):
res += [item+[num] for item in res]
return res
"""
Given a collection of integers that might contain duplicates, nums,
return all possible subsets.
Note: The solution set must not contain duplicate subsets.
For example,
If nums = [1,2,2], a solution is:
[
[2],
[1],
[1,2,2],
[2,2],
[1,2],
[]
]
"""
def subsets_unique(nums):
def backtrack(res, nums, stack, pos):
if pos == len(nums):
res.add(tuple(stack))
else:
# take
stack.append(nums[pos])
backtrack(res, nums, stack, pos+1)
stack.pop()
# don't take
backtrack(res, nums, stack, pos+1)
res = set()
backtrack(res, nums, [], 0)
return list(res)
from collections import deque
'''
BFS time complexity : O(|E| + |V|)
BFS space complexity : O(|E| + |V|)
do BFS from (0,0) of the grid and get the minimum number of steps needed to get to the lower right column
only step on the columns whose value is 1
if there is no path, it returns -1
Ex 1)
If grid is
[[1,0,1,1,1,1],
[1,0,1,0,1,0],
[1,0,1,0,1,1],
[1,1,1,0,1,1]],
the answer is: 14
Ex 2)
If grid is
[[1,0,0],
[0,1,1],
[0,1,1]],
the answer is: -1
'''
def maze_search(maze):
BLOCKED, ALLOWED = 0, 1
UNVISITED, VISITED = 0, 1
initial_x, initial_y = 0, 0
if maze[initial_x][initial_y] == BLOCKED:
return -1
directions = [(0, -1), (0, 1), (-1, 0), (1, 0)]
height, width = len(maze), len(maze[0])
target_x, target_y = height - 1, width - 1
queue = deque([(initial_x, initial_y, 0)])
is_visited = [[UNVISITED for w in range(width)] for h in range(height)]
is_visited[initial_x][initial_y] = VISITED
while queue:
x, y, steps = queue.popleft()
if x == target_x and y == target_y:
return steps
for dx, dy in directions:
new_x = x + dx
new_y = y + dy
if not (0 <= new_x < height and 0 <= new_y < width):
continue
if maze[new_x][new_y] == ALLOWED and is_visited[new_x][new_y] == UNVISITED:
queue.append((new_x, new_y, steps + 1))
is_visited[new_x][new_y] = VISITED
return -1
import collections
"""
do BFS from each building, and decrement all empty place for every building visit
when grid[i][j] == -b_nums, it means that grid[i][j] are already visited from all b_nums
and use dist to record distances from b_nums
"""
def shortest_distance(grid):
if not grid or not grid[0]:
return -1
matrix = [[[0,0] for i in range(len(grid[0]))] for j in range(len(grid))]
count = 0 # count how many building we have visited
for i in range(len(grid)):
for j in range(len(grid[0])):
if grid[i][j] == 1:
bfs(grid, matrix, i, j, count)
count += 1
res = float('inf')
for i in range(len(matrix)):
for j in range(len(matrix[0])):
if matrix[i][j][1]==count:
res = min(res, matrix[i][j][0])
return res if res!=float('inf') else -1
def bfs(grid, matrix, i, j, count):
q = [(i, j, 0)]
while q:
i, j, step = q.pop(0)
for k, l in [(i-1,j), (i+1,j), (i,j-1), (i,j+1)]:
# only the position be visited by count times will append to queue
if 0<=k<len(grid) and 0<=l<len(grid[0]) and \
matrix[k][l][1]==count and grid[k][l]==0:
matrix[k][l][0] += step+1
matrix[k][l][1] = count+1
q.append((k, l, step+1))
"""
Given two words (begin_word and end_word), and a dictionary's word list,
find the length of shortest transformation sequence
from beginWord to endWord, such that:
Only one letter can be changed at a time
Each intermediate word must exist in the word list
For example,
Given:
begin_word = "hit"
end_word = "cog"
word_list = ["hot","dot","dog","lot","log"]
As one shortest transformation is "hit" -> "hot" -> "dot" -> "dog" -> "cog",
return its length 5.
Note:
Return -1 if there is no such transformation sequence.
All words have the same length.
All words contain only lowercase alphabetic characters.
"""
def ladder_length(begin_word, end_word, word_list):
"""
Bidirectional BFS!!!
:type begin_word: str
:type end_word: str
:type word_list: Set[str]
:rtype: int
"""
if len(begin_word) != len(end_word):
return -1 # not possible
if begin_word == end_word:
return 0
# when only differ by 1 character
if sum(c1 != c2 for c1, c2 in zip(begin_word, end_word)) == 1:
return 1
begin_set = set()
end_set = set()
begin_set.add(begin_word)
end_set.add(end_word)
result = 2
while begin_set and end_set:
if len(begin_set) > len(end_set):
begin_set, end_set = end_set, begin_set
next_begin_set = set()
for word in begin_set:
for ladder_word in word_range(word):
if ladder_word in end_set:
return result
if ladder_word in word_list:
next_begin_set.add(ladder_word)
word_list.remove(ladder_word)
begin_set = next_begin_set
result += 1
# print(begin_set)
# print(result)
return -1
def word_range(word):
for ind in range(len(word)):
temp = word[ind]
for c in [chr(x) for x in range(ord('a'), ord('z') + 1)]:
if c != temp:
yield word[:ind] + c + word[ind + 1:]
"""
The following code adds two positive integers without using the '+' operator.
The code uses bitwise operations to add two numbers.
Input: 2 3
Output: 5
"""
def add_bitwise_operator(x, y):
while y:
carry = x & y
x = x ^ y
y = carry << 1
return x
"""
Fundamental bit operation:
get_bit(num, i): get an exact bit at specific index
set_bit(num, i): set a bit at specific index
clear_bit(num, i): clear a bit at specific index
update_bit(num, i, bit): update a bit at specific index
"""
"""
This function shifts 1 over by i bits, creating a value being like 0001000. By
performing an AND with num, we clear all bits other than the bit at bit i.
Finally we compare that to 0
"""
def get_bit(num, i):
return (num & (1 << i)) != 0
"""
This function shifts 1 over by i bits, creating a value being like 0001000. By
performing an OR with num, only value at bit i will change.
"""
def set_bit(num, i):
return num | (1 << i)
"""
This method operates in almost the reverse of set_bit
"""
def clear_bit(num, i):
mask = ~(1 << i)
return num & mask
"""
To set the ith bit to value, we first clear the bit at position i by using a
mask. Then, we shift the intended value. Finally we OR these two numbers
"""
def update_bit(num, i, bit):
mask = ~(1 << i)
return (num & mask) | (bit << i)
from collections import deque
def int_to_bytes_big_endian(num):
bytestr = deque()
while num > 0:
# list.insert(0, ...) is inefficient
bytestr.appendleft(num & 0xff)
num >>= 8
return bytes(bytestr)
def int_to_bytes_little_endian(num):
bytestr = []
while num > 0:
bytestr.append(num & 0xff)
num >>= 8
return bytes(bytestr)
def bytes_big_endian_to_int(bytestr):
num = 0
for b in bytestr:
num <<= 8
num += b
return num
def bytes_little_endian_to_int(bytestr):
num = 0
e = 0
for b in bytestr:
num += b << e
e += 8
return num
"""
Write a function to determine the minimal number of bits you would need to
flip to convert integer A to integer B.
For example:
Input: 29 (or: 11101), 15 (or: 01111)
Output: 2
"""
def count_flips_to_convert(a, b):
diff = a ^ b
# count number of ones in diff
count = 0
while diff:
diff &= (diff - 1)
count += 1
return count
"""
Write a function that takes an unsigned integer and
returns the number of '1' bits it has
(also known as the Hamming weight).
For example, the 32-bit integer '11' has binary
representation 00000000000000000000000000001011,
so the function should return 3.
T(n)- O(k) : k is the number of 1s present in binary representation.
NOTE: this complexity is better than O(log n).
e.g. for n = 00010100000000000000000000000000
only 2 iterations are required.
Number of loops is
equal to the number of 1s in the binary representation."""
def count_ones_recur(n):
"""Using Brian Kernighan's Algorithm. (Recursive Approach)"""
if not n:
return 0
return 1 + count_ones_recur(n & (n-1))
def count_ones_iter(n):
"""Using Brian Kernighan's Algorithm. (Iterative Approach)"""
count = 0
while n:
n &= (n-1)
count += 1
return count
"""
Given two strings s and t which consist of only lowercase letters.
String t is generated by random shuffling string s and then add one more letter
at a random position. Find the letter that was added in t.
For example:
Input:
s = "abcd"
t = "abecd"
Output: 'e'
Explanation:
'e' is the letter that was added.
"""
"""
We use the characteristic equation of XOR.
A xor B xor C = A xor C xor B
If A == C, then A xor C = 0
and then, B xor 0 = B
"""
def find_difference(s, t):
ret = 0
for ch in s + t:
# ord(ch) return an integer representing the Unicode code point of that character
ret = ret ^ ord(ch)
# chr(i) Return the string representing a character whose Unicode code point is the integer i
return chr(ret)
"""
Returns the missing number from a sequence of unique integers
in range [0..n] in O(n) time and space. The difference between
consecutive integers cannot be more than 1. If the sequence is
already complete, the next integer in the sequence will be returned.
For example:
Input: nums = [4, 1, 3, 0, 6, 5, 2]
Output: 7
"""
def find_missing_number(nums):
missing = 0
for i, num in enumerate(nums):
missing ^= num
missing ^= i + 1
return missing
def find_missing_number2(nums):
num_sum = sum(nums)
n = len(nums)
total_sum = n*(n+1) // 2
missing = total_sum - num_sum
return missing
"""
You have an integer and you can flip exactly one bit from a 0 to 1.
Write code to find the length of the longest sequence of 1s you could create.
For example:
Input: 1775 ( or: 11011101111)
Output: 8
"""
def flip_bit_longest_seq(num):
curr_len = 0
prev_len = 0
max_len = 0
while num:
if num & 1 == 1: # last digit is 1
curr_len += 1
elif num & 1 == 0: # last digit is 0
if num & 2 == 0: # second last digit is 0
prev_len = 0
else:
prev_len = curr_len
curr_len = 0
max_len = max(max_len, prev_len + curr_len)
num = num >> 1 # right shift num
return max_len + 1
"""
given an integer, write a function to determine if it is a power of two
"""
def is_power_of_two(n):
"""
:type n: int
:rtype: bool
"""
return n > 0 and not n & (n-1)
"""
Reverse bits of a given 32 bits unsigned integer.
For example, given input 43261596
(represented in binary as 00000010100101000001111010011100),
return 964176192
(represented in binary as 00111001011110000010100101000000).
"""
def reverse_bits(n):
m = 0
i = 0
while i < 32:
m = (m << 1) + (n & 1)
n >>= 1
i += 1
return m
"""
Given an array of integers, every element appears
twice except for one. Find that single one.
NOTE: This also works for finding a number occurring odd
number of times, where all the other numbers appear
even number of times.
Note:
Your algorithm should have a linear runtime complexity.
Could you implement it without using extra memory?
"""
def single_number(nums):
"""
Returns single number, if found.
Else if all numbers appear twice, returns 0.
:type nums: List[int]
:rtype: int
"""
i = 0
for num in nums:
i ^= num
return i
"""
Given an array of integers, every element appears
three times except for one, which appears exactly once.
Find that single one.
Note:
Your algorithm should have a linear runtime complexity.
Could you implement it without using extra memory?
Solution:
32 bits for each integer.
Consider 1 bit in it, the sum of each integer's corresponding bit
(except for the single number)
should be 0 if mod by 3. Hence, we sum the bits of all
integers and mod by 3,
the remaining should be the exact bit of the single number.
In this way, you get the 32 bits of the single number.
"""
# Another awesome answer
def single_number2(nums):
ones, twos = 0, 0
for i in range(len(nums)):
ones = (ones ^ nums[i]) & ~twos
twos = (twos ^ nums[i]) & ~ones
return ones
"""
Given an array of numbers nums,
in which exactly two elements appear only once
and all the other elements appear exactly twice.
Find the two elements that appear only once.
Limitation: Time Complexity: O(N) and Space Complexity O(1)
For example:
Given nums = [1, 2, 1, 3, 2, 5], return [3, 5].
Note:
The order of the result is not important.
So in the above example, [5, 3] is also correct.
Solution:
1. Use XOR to cancel out the pairs and isolate A^B
2. It is guaranteed that at least 1 bit exists in A^B since
A and B are different numbers. ex) 010 ^ 111 = 101
3. Single out one bit R (right most bit in this solution) to use it as a pivot
4. Divide all numbers into two groups.
One group with a bit in the position R
One group without a bit in the position R
5. Use the same strategy we used in step 1 to isolate A and B from each group.
"""
def single_number3(nums):
"""
:type nums: List[int]
:rtype: List[int]
"""
# isolate a^b from pairs using XOR
ab = 0
for n in nums:
ab ^= n
# isolate right most bit from a^b
right_most = ab & (-ab)
# isolate a and b from a^b
a, b = 0, 0
for n in nums:
if n & right_most:
a ^= n
else:
b ^= n
return [a, b]
"""
Given a set of distinct integers, nums,
return all possible subsets.
Note: The solution set must not contain duplicate subsets.
For example,
If nums = [1,2,3], a solution is:
{
(1, 2),
(1, 3),
(1,),
(2,),
(3,),
(1, 2, 3),
(),
(2, 3)
}
"""
def subsets(nums):
"""
:param nums: List[int]
:return: Set[tuple]
"""
n = len(nums)
total = 1 << n
res = set()
for i in range(total):
subset = tuple(num for j, num in enumerate(nums) if i & 1 << j)
res.add(subset)
return res
"""
this explanation is from leet_nik @ leetcode
This is an amazing solution. Learnt a lot.
Number of subsets for {1 , 2 , 3 } = 2^3 .
why ?
case possible outcomes for the set of subsets
1 -> Take or dont take = 2
2 -> Take or dont take = 2
3 -> Take or dont take = 2
therefore,
total = 2*2*2 = 2^3 = {{}, {1}, {2}, {3}, {1,2}, {1,3}, {2,3}, {1,2,3}}
Lets assign bits to each outcome ->
First bit to 1 , Second bit to 2 and third bit to 3
Take = 1
Dont take = 0
0) 0 0 0 -> Dont take 3 , Dont take 2 , Dont take 1 = { }
1) 0 0 1 -> Dont take 3 , Dont take 2 , take 1 = { 1 }
2) 0 1 0 -> Dont take 3 , take 2 , Dont take 1 = { 2 }
3) 0 1 1 -> Dont take 3 , take 2 , take 1 = { 1 , 2 }
4) 1 0 0 -> take 3 , Dont take 2 , Dont take 1 = { 3 }
5) 1 0 1 -> take 3 , Dont take 2 , take 1 = { 1 , 3 }
6) 1 1 0 -> take 3 , take 2 , Dont take 1 = { 2 , 3 }
7) 1 1 1 -> take 3 , take 2 , take 1 = { 1 , 2 , 3 }
In the above logic ,Insert S[i] only if (j>>i)&1 ==true
{ j E { 0,1,2,3,4,5,6,7 } i = ith element in the input array }
element 1 is inserted only into those places where 1st bit of j is 1
if( j >> 0 &1 ) ==> for above above eg.
this is true for sl.no.( j )= 1 , 3 , 5 , 7
element 2 is inserted only into those places where 2nd bit of j is 1
if( j >> 1 &1 ) == for above above eg.
this is true for sl.no.( j ) = 2 , 3 , 6 , 7
element 3 is inserted only into those places where 3rd bit of j is 1
if( j >> 2 & 1 ) == for above above eg.
this is true for sl.no.( j ) = 4 , 5 , 6 , 7
Time complexity : O(n*2^n) , for every input element loop traverses
the whole solution set length i.e. 2^n
"""
"""
Swap_pair: A function swap odd and even bits in an integer with as few instructions
as possible (Ex bit and bit 1 are swapped, bit 2 and bit 3 are swapped)
For example:
22: 010110 --> 41: 101001
10: 1010 --> 5 : 0101
"""
"""
We can approach this as operating on the odds bit first, and then the even bits.
We can mask all odd bits with 10101010 in binary ('AA') then shift them right by 1
Similarly, we mask all even bit with 01010101 in binary ('55') then shift them left
by 1. Finally, we merge these two values by OR operation.
"""
def swap_pair(num):
# odd bit arithmetic right shift 1 bit
odd = (num & int('AAAAAAAA', 16)) >> 1
# even bit left shift 1 bit
even = (num & int('55555555', 16)) << 1
return odd | even
"""
Given a positive integer, check whether it has alternating bits: namely,
if two adjacent bits will always have different values.
For example:
Input: 5
Output: True because the binary representation of 5 is: 101.
Input: 7
Output: False because the binary representation of 7 is: 111.
Input: 11
Output: False because the binary representation of 11 is: 1011.
Input: 10
Output: True because The binary representation of 10 is: 1010.
"""
# Time Complexity - O(number of bits in n)
def has_alternative_bit(n):
first_bit = 0
second_bit = 0
while n:
first_bit = n & 1
if n >> 1:
second_bit = (n >> 1) & 1
if not first_bit ^ second_bit:
return False
else:
return True
n = n >> 1
return True
# Time Complexity - O(1)
def has_alternative_bit_fast(n):
mask1 = int('aaaaaaaa', 16) # for bits ending with zero (...1010)
mask2 = int('55555555', 16) # for bits ending with one (...0101)
return mask1 == (n + (n ^ mask1)) or mask2 == (n + (n ^ mask2))
"""
Insertion:
insert_one_bit(num, bit, i): insert exact one bit at specific position
For example:
Input: num = 10101 (21)
insert_one_bit(num, 1, 2): 101101 (45)
insert_one_bit(num, 0, 2): 101001 (41)
insert_one_bit(num, 1, 5): 110101 (53)
insert_one_bit(num, 1, 0): 101011 (43)
insert_mult_bits(num, bits, len, i): insert multiple bits with len at specific position
For example:
Input: num = 101 (5)
insert_mult_bits(num, 7, 3, 1): 101111 (47)
insert_mult_bits(num, 7, 3, 0): 101111 (47)
insert_mult_bits(num, 7, 3, 3): 111101 (61)
"""
"""
Insert exact one bit at specific position
Algorithm:
1. Create a mask having bit from i to the most significant bit, and append the new bit at 0 position
2. Keep the bit from 0 position to i position ( like 000...001111)
3. Merge mask and num
"""
def insert_one_bit(num, bit, i):
# Create mask
mask = num >> i
mask = (mask << 1) | bit
mask = mask << i
# Keep the bit from 0 position to i position
right = ((1 << i) - 1) & num
return right | mask
def insert_mult_bits(num, bits, len, i):
mask = num >> i
mask = (mask << len) | bits
mask = mask << i
right = ((1 << i) - 1) & num
return right | mask
"""
Remove_bit(num, i): remove a bit at specific position.
For example:
Input: num = 10101 (21)
remove_bit(num, 2): output = 1001 (9)
remove_bit(num, 4): output = 101 (5)
remove_bit(num, 0): output = 1010 (10)
"""
def remove_bit(num, i):
mask = num >> (i + 1)
mask = mask << i
right = ((1 << i) - 1) & num
return mask | right
"""
Given a positive integer N, find and return the longest distance between two
consecutive 1' in the binary representation of N.
If there are not two consecutive 1's, return 0
For example:
Input: 22
Output: 2
Explanation:
22 in binary is 10110
In the binary representation of 22, there are three ones, and two consecutive pairs of 1's.
The first consecutive pair of 1's have distance 2.
The second consecutive pair of 1's have distance 1.
The answer is the largest of these two distances, which is 2
"""
# 原方法为 binary_gap,但通过实验发现算法有误,不论是什么数,输出值最多为2。
# 改进方法为binary_gap_improved。
# The original method is binary_gap,
# but the experimental results show that the algorithm seems to be wrong,
# regardless of the number, the output value is up to 2.
# The improved method is binary_gap_improved.
def binary_gap(N):
last = None
ans = 0
index = 0
while N != 0:
if N & 1:
if last is not None:
ans = max(ans, index - last)
last = index
index = index + 1
N = N >> 1
return ans
def binary_gap_improved(N):
last = None
ans = 0
index = 0
while N != 0:
tes = N & 1
if tes:
if last is not None:
ans = max(ans, index - last + 1)
else:
last = index
else:
last = index + 1
index = index + 1
N = N >> 1
return ans
print(binary_gap(111))
print(binary_gap_improved(111))
"""
Huffman coding is an efficient method of compressing data without losing information.
This algorithm analyzes the symbols that appear in a message.
Symbols that appear more often will be encoded as a shorter-bit string
while symbols that aren't used as much will be encoded as longer strings.
"""
from collections import defaultdict, deque
import heapq
class Node:
def __init__(self, frequency=0, sign=None, left=None, right=None):
self.frequency = frequency
self.sign = sign
self.left = left
self.right = right
def __lt__(self, other):
return self.frequency < other.frequency
def __gt__(self, other):
return self.frequency > other.frequency
def __eq__(self, other):
return self.frequency == other.frequency
def __str__(self):
return "<ch: {0}: {1}>".format(self.sign, self.frequency)
def __repr__(self):
return "<ch: {0}: {1}>".format(self.sign, self.frequency)
class HuffmanReader:
def __init__(self, file):
self.file = file
self.buffer = []
self.is_last_byte = False
def get_number_of_additional_bits_in_the_last_byte(self) -> int:
bin_num = self.get_bit() + self.get_bit() + self.get_bit()
return int(bin_num, 2)
def load_tree(self) -> Node:
"""
Load tree from file
:return:
"""
node_stack = deque()
queue_leaves = deque()
root = Node()
current_node = root
is_end_of_tree = False
while not is_end_of_tree:
current_bit = self.get_bit()
if current_bit == "0":
current_node.left = Node()
current_node.right = Node()
node_stack.append(current_node.right) # going to left node, right push on stack
current_node = current_node.left
else:
queue_leaves.append(current_node)
if node_stack:
current_node = node_stack.pop()
else:
is_end_of_tree = True
self._fill_tree(queue_leaves)
return root
def _fill_tree(self, leaves_queue):
"""
Load values to tree after reading tree
:param leaves_queue:
:return:
"""
leaves_queue.reverse()
while leaves_queue:
node = leaves_queue.pop()
s = int(self.get_byte(), 2)
node.sign = s
def _load_byte(self, buff_limit=8) -> bool:
"""
Load next byte is buffer is less than buff_limit
:param buff_limit:
:return: True if there is enough bits in buffer to read
"""
if len(self.buffer) <= buff_limit:
byte = self.file.read(1)
if not byte:
return False
i = int.from_bytes(byte, "big")
self.buffer.extend(list("{0:08b}".format(i)))
return True
def get_bit(self, buff_limit=8):
if self._load_byte(buff_limit):
bit = self.buffer.pop(0)
return bit
else:
return -1
def get_byte(self):
if self._load_byte():
byte_list = self.buffer[:8]
self.buffer = self.buffer[8:]
return "".join(byte_list)
else:
return -1
class HuffmanWriter:
def __init__(self, file):
self.file = file
self.buffer = ""
self.saved_bits = 0
def write_char(self, char):
self.write_int(ord(char))
def write_int(self, num):
bin_int = "{0:08b}".format(num)
self.write_bits(bin_int)
def write_bits(self, bits):
self.saved_bits += len(bits)
self.buffer += bits
while len(self.buffer) >= 8:
i = int(self.buffer[:8], 2)
self.file.write(bytes([i]))
self.buffer = self.buffer[8:]
def save_tree(self, tree):
"""
Generate and save tree code to file
:param tree:
:return:
"""
signs = []
tree_code = ""
def get_code_tree(T):
nonlocal tree_code
if T.sign is not None:
signs.append(T.sign)
if T.left:
tree_code += "0"
get_code_tree(T.left)
if T.right:
tree_code += "1"
get_code_tree(T.right)
get_code_tree(tree)
self.write_bits(tree_code + "1") # "1" indicates that tree ended (it will be needed to load the tree)
for int_sign in signs:
self.write_int(int_sign)
def _save_information_about_additional_bits(self, additional_bits: int):
"""
Overwrite first three bits in the file
:param additional_bits: number of bits that were appended to fill last byte
:return:
"""
self.file.seek(0)
first_byte_raw = self.file.read(1)
self.file.seek(0)
first_byte = "{0:08b}".format(int.from_bytes(first_byte_raw, "big"))
# overwrite first three bits
first_byte = first_byte[3:]
first_byte = "{0:03b}".format(additional_bits) + first_byte
self.write_bits(first_byte)
def close(self):
additional_bits = 8 - len(self.buffer)
if additional_bits != 8: # buffer is empty, no need to append extra "0"
self.write_bits("0" * additional_bits)
self._save_information_about_additional_bits(additional_bits)
class TreeFinder:
"""
Class to help find signs in tree
"""
def __init__(self, tree):
self.root = tree
self.current_node = tree
self.found = None
def find(self, bit):
"""
Find sign in tree
:param bit:
:return: True if sign is found
"""
if bit == "0":
self.current_node = self.current_node.left
elif bit == "1":
self.current_node = self.current_node.right
else:
self._reset()
return True
if self.current_node.sign is not None:
self._reset(self.current_node.sign)
return True
else:
return False
def _reset(self, found=""):
self.found = found
self.current_node = self.root
class HuffmanCoding:
def __init__(self):
pass
@staticmethod
def decode_file(file_in_name, file_out_name):
with open(file_in_name, "rb") as file_in, open(file_out_name, "wb") as file_out:
reader = HuffmanReader(file_in)
additional_bits = reader.get_number_of_additional_bits_in_the_last_byte()
tree = reader.load_tree()
HuffmanCoding._decode_and_write_signs_to_file(file_out, reader, tree, additional_bits)
print("File decoded.")
@staticmethod
def _decode_and_write_signs_to_file(file, reader: HuffmanReader, tree: Node, additional_bits: int):
tree_finder = TreeFinder(tree)
is_end_of_file = False
while not is_end_of_file:
bit = reader.get_bit()
if bit != -1:
while not tree_finder.find(bit): # read whole code
bit = reader.get_bit(0)
file.write(bytes([tree_finder.found]))
else: # There is last byte in buffer to parse
is_end_of_file = True
last_byte = reader.buffer
last_byte = last_byte[:-additional_bits] # remove additional "0" used to fill byte
for bit in last_byte:
if tree_finder.find(bit):
file.write(bytes([tree_finder.found]))
@staticmethod
def encode_file(file_in_name, file_out_name):
with open(file_in_name, "rb") as file_in, open(file_out_name, mode="wb+") as file_out:
signs_frequency = HuffmanCoding._get_char_frequency(file_in)
file_in.seek(0)
tree = HuffmanCoding._create_tree(signs_frequency)
codes = HuffmanCoding._generate_codes(tree)
writer = HuffmanWriter(file_out)
writer.write_bits("000") # leave space to save how many bits will be appended to fill the last byte
writer.save_tree(tree)
HuffmanCoding._encode_and_write_signs_to_file(file_in, writer, codes)
writer.close()
print("File encoded.")
@staticmethod
def _encode_and_write_signs_to_file(file, writer: HuffmanWriter, codes: dict):
sign = file.read(1)
while sign:
int_char = int.from_bytes(sign, "big")
writer.write_bits(codes[int_char])
sign = file.read(1)
@staticmethod
def _get_char_frequency(file) -> dict:
is_end_of_file = False
signs_frequency = defaultdict(lambda: 0)
while not is_end_of_file:
prev_pos = file.tell()
sign = file.read(1)
curr_pos = file.tell()
if prev_pos == curr_pos:
is_end_of_file = True
else:
signs_frequency[int.from_bytes(sign, "big")] += 1
return signs_frequency
@staticmethod
def _generate_codes(tree: Node) -> dict:
codes = dict()
HuffmanCoding._go_through_tree_and_create_codes(tree, "", codes)
return codes
@staticmethod
def _create_tree(signs_frequency: dict) -> Node:
nodes = [Node(frequency=frequency, sign=char_int) for char_int, frequency in signs_frequency.items()]
heapq.heapify(nodes)
while len(nodes) > 1:
left = heapq.heappop(nodes)
right = heapq.heappop(nodes)
new_node = Node(frequency=left.frequency + right.frequency, left=left, right=right)
heapq.heappush(nodes, new_node)
return nodes[0] # root
@staticmethod
def _go_through_tree_and_create_codes(tree: Node, code: str, dict_codes: dict):
if tree.sign is not None:
dict_codes[tree.sign] = code
if tree.left:
HuffmanCoding._go_through_tree_and_create_codes(tree.left, code + "0", dict_codes)
if tree.right:
HuffmanCoding._go_through_tree_and_create_codes(tree.right, code + "1", dict_codes)
"""
Run-length encoding (RLE) is a simple compression algorithm
that gets a stream of data as the input and returns a
sequence of counts of consecutive data values in a row.
When decompressed the data will be fully recovered as RLE
is a lossless data compression.
"""
def encode_rle(input):
"""
Gets a stream of data and compresses it
under a Run-Length Encoding.
:param input: The data to be encoded.
:return: The encoded string.
"""
if not input: return ''
encoded_str = ''
prev_ch = ''
count = 1
for ch in input:
# Check If the subsequent character does not match
if ch != prev_ch:
# Add the count and character
if prev_ch:
encoded_str += str(count) + prev_ch
# Reset the count and set the character
count = 1
prev_ch = ch
else:
# Otherwise increment the counter
count += 1
else:
return encoded_str + (str(count) + prev_ch)
def decode_rle(input):
"""
Gets a stream of data and decompresses it
under a Run-Length Decoding.
:param input: The data to be decoded.
:return: The decoded string.
"""
decode_str = ''
count = ''
for ch in input:
# If not numerical
if not ch.isdigit():
# Expand it for the decoding
decode_str += ch * int(count)
count = ''
else:
# Add it in the counter
count += ch
return decode_str
"""
Elias γ code or Elias gamma code is a universal code encoding positive integers.
It is used most commonly when coding integers whose upper-bound cannot be determined beforehand.
Elias δ code or Elias delta code is a universal code encoding the positive integers,
that includes Elias γ code when calculating.
Both were developed by Peter Elias.
"""
from math import log,ceil
log2 = lambda x: log(x,2)
# Calculates the binary number
def binary(x,l=1):
fmt = '{0:0%db}' % l
return fmt.format(x)
# Calculates the unary number
def unary(x):
return (x-1)*'1'+'0'
def elias_generic(lencoding, x):
"""
The compressed data is calculated in two parts.
The first part is the unary number of 1 + ⌊log2(x)⌋.
The second part is the binary number of x - 2^(⌊log2(x)⌋).
For the final result we add these two parts.
"""
if x == 0: return '0'
first_part = 1 + int(log2(x))
a = x - 2**(int(log2(x)))
k = int(log2(x))
return lencoding(first_part) + binary(a,k)
def elias_gamma(x):
"""
For the first part we put the unary number of x.
"""
return elias_generic(unary, x)
def elias_delta(x):
"""
For the first part we put the elias_g of the number.
"""
return elias_generic(elias_gamma,x)
"""
Numbers can be regarded as product of its factors. For example,
8 = 2 x 2 x 2;
= 2 x 4.
Write a function that takes an integer n and return all possible combinations
of its factors.Numbers can be regarded as product of its factors. For example,
8 = 2 x 2 x 2;
= 2 x 4.
Examples:
input: 1
output:
[]
input: 37
output:
[]
input: 32
output:
[
[2, 16],
[2, 2, 8],
[2, 2, 2, 4],
[2, 2, 2, 2, 2],
"""
def get_factors(n):
"""[summary]
Arguments:
n {[int]} -- [to analysed number]
Returns:
[list of lists] -- [all factors of the number n]
"""
def factor(n, i, combi, res):
"""[summary]
helper function
Arguments:
n {[int]} -- [number]
i {[int]} -- [to tested divisor]
combi {[list]} -- [catch divisors]
res {[list]} -- [all factors of the number n]
Returns:
[list] -- [res]
"""
while i * i <= n:
if n % i == 0:
res += combi + [i, int(n/i)],
factor(n/i, i, combi+[i], res)
i += 1
return res
return factor(n, 2, [], [])
def get_factors_iterative1(n):
"""[summary]
Computes all factors of n.
Translated the function get_factors(...) in
a call-stack modell.
Arguments:
n {[int]} -- [to analysed number]
Returns:
[list of lists] -- [all factors]
"""
todo, res = [(n, 2, [])], []
while todo:
n, i, combi = todo.pop()
while i * i <= n:
if n % i == 0:
res += combi + [i, n//i],
todo.append((n//i, i, combi+[i])),
i += 1
return res
def get_factors_iterative2(n):
"""[summary]
analog as above
Arguments:
n {[int]} -- [description]
Returns:
[list of lists] -- [all factors of n]
"""
ans, stack, x = [], [], 2
while True:
if x > n // x:
if not stack:
return ans
ans.append(stack + [n])
x = stack.pop()
n *= x
x += 1
elif n % x == 0:
stack.append(x)
n //= x
else:
x += 1
"""
Given a 2d grid map of '1's (land) and '0's (water),
count the number of islands.
An island is surrounded by water and is formed by
connecting adjacent lands horizontally or vertically.
You may assume all four edges of the grid are all surrounded by water.
Example 1:
11110
11010
11000
00000
Answer: 1
Example 2:
11000
11000
00100
00011
Answer: 3
"""
def num_islands(grid):
count = 0
for i in range(len(grid)):
for j, col in enumerate(grid[i]):
if col == 1:
dfs(grid, i, j)
count += 1
return count
def dfs(grid, i, j):
if (i < 0 or i >= len(grid)) or (j < 0 or j >= len(grid[0])):
return
if grid[i][j] != 1:
return
grid[i][j] = 0
dfs(grid, i+1, j)
dfs(grid, i-1, j)
dfs(grid, i, j+1)
dfs(grid, i, j-1)
# Given an m x n matrix of non-negative integers representing
# the height of each unit cell in a continent,
# the "Pacific ocean" touches the left and top edges of the matrix
# and the "Atlantic ocean" touches the right and bottom edges.
# Water can only flow in four directions (up, down, left, or right)
# from a cell to another one with height equal or lower.
# Find the list of grid coordinates where water can flow to both the
# Pacific and Atlantic ocean.
# Note:
# The order of returned grid coordinates does not matter.
# Both m and n are less than 150.
# Example:
# Given the following 5x5 matrix:
# Pacific ~ ~ ~ ~ ~
# ~ 1 2 2 3 (5) *
# ~ 3 2 3 (4) (4) *
# ~ 2 4 (5) 3 1 *
# ~ (6) (7) 1 4 5 *
# ~ (5) 1 1 2 4 *
# * * * * * Atlantic
# Return:
# [[0, 4], [1, 3], [1, 4], [2, 2], [3, 0], [3, 1], [4, 0]]
# (positions with parentheses in above matrix).
def pacific_atlantic(matrix):
"""
:type matrix: List[List[int]]
:rtype: List[List[int]]
"""
n = len(matrix)
if not n: return []
m = len(matrix[0])
if not m: return []
res = []
atlantic = [[False for _ in range (n)] for _ in range(m)]
pacific = [[False for _ in range (n)] for _ in range(m)]
for i in range(n):
dfs(pacific, matrix, float("-inf"), i, 0)
dfs(atlantic, matrix, float("-inf"), i, m-1)
for i in range(m):
dfs(pacific, matrix, float("-inf"), 0, i)
dfs(atlantic, matrix, float("-inf"), n-1, i)
for i in range(n):
for j in range(m):
if pacific[i][j] and atlantic[i][j]:
res.append([i, j])
return res
def dfs(grid, matrix, height, i, j):
if i < 0 or i >= len(matrix) or j < 0 or j >= len(matrix[0]):
return
if grid[i][j] or matrix[i][j] < height:
return
grid[i][j] = True
dfs(grid, matrix, matrix[i][j], i-1, j)
dfs(grid, matrix, matrix[i][j], i+1, j)
dfs(grid, matrix, matrix[i][j], i, j-1)
dfs(grid, matrix, matrix[i][j], i, j+1)
"""
It's similar to how human solve Sudoku.
create a hash table (dictionary) val to store possible values in every location.
Each time, start from the location with fewest possible values, choose one value
from it and then update the board and possible values at other locations.
If this update is valid, keep solving (DFS). If this update is invalid (leaving
zero possible values at some locations) or this value doesn't lead to the
solution, undo the updates and then choose the next value.
Since we calculated val at the beginning and start filling the board from the
location with fewest possible values, the amount of calculation and thus the
runtime can be significantly reduced:
The run time is 48-68 ms on LeetCode OJ, which seems to be among the fastest
python solutions here.
The PossibleVals function may be further simplified/optimized, but it works just
fine for now. (it would look less lengthy if we are allowed to use numpy array
for the board lol).
"""
class Sudoku:
def __init__ (self, board, row, col):
self.board = board
self.row = row
self.col = col
self.val = self.possible_values()
def possible_values(self):
a = "123456789"
d, val = {}, {}
for i in range(self.row):
for j in range(self.col):
ele = self.board[i][j]
if ele != ".":
d[("r", i)] = d.get(("r", i), []) + [ele]
d[("c", j)] = d.get(("c", j), []) + [ele]
d[(i//3, j//3)] = d.get((i//3, j//3), []) + [ele]
else:
val[(i,j)] = []
for (i,j) in val.keys():
inval = d.get(("r",i),[])+d.get(("c",j),[])+d.get((i/3,j/3),[])
val[(i,j)] = [n for n in a if n not in inval ]
return val
def solve(self):
if len(self.val)==0:
return True
kee = min(self.val.keys(), key=lambda x: len(self.val[x]))
nums = self.val[kee]
for n in nums:
update = {kee:self.val[kee]}
if self.valid_one(n, kee, update): # valid choice
if self.solve(): # keep solving
return True
self.undo(kee, update) # invalid choice or didn't solve it => undo
return False
def valid_one(self, n, kee, update):
self.board[kee[0]][kee[1]] = n
del self.val[kee]
i, j = kee
for ind in self.val.keys():
if n in self.val[ind]:
if ind[0]==i or ind[1]==j or (ind[0]/3,ind[1]/3)==(i/3,j/3):
update[ind] = n
self.val[ind].remove(n)
if len(self.val[ind])==0:
return False
return True
def undo(self, kee, update):
self.board[kee[0]][kee[1]]="."
for k in update:
if k not in self.val:
self.val[k]= update[k]
else:
self.val[k].append(update[k])
return None
def __str__(self):
"""[summary]
Generates a board representation as string.
Returns:
[str] -- [board representation]
"""
resp = ""
for i in range(self.row):
for j in range(self.col):
resp += " {0} ".format(self.board[i][j])
resp += "\n"
return resp
"""
You are given a m x n 2D grid initialized with these three possible values:
-1: A wall or an obstacle.
0: A gate.
INF: Infinity means an empty room. We use the value 2^31 - 1 = 2147483647 to represent INF
as you may assume that the distance to a gate is less than 2147483647.
Fill the empty room with distance to its nearest gate.
If it is impossible to reach a gate, it should be filled with INF.
For example, given the 2D grid:
INF -1 0 INF
INF INF INF -1
INF -1 INF -1
0 -1 INF INF
After running your function, the 2D grid should be:
3 -1 0 1
2 2 1 -1
1 -1 2 -1
0 -1 3 4
"""
def walls_and_gates(rooms):
for i in range(len(rooms)):
for j in range(len(rooms[0])):
if rooms[i][j] == 0:
dfs(rooms, i, j, 0)
def dfs(rooms, i, j, depth):
if (i < 0 or i >= len(rooms)) or (j < 0 or j >= len(rooms[0])):
return # out of bounds
if rooms[i][j] < depth:
return # crossed
rooms[i][j] = depth
dfs(rooms, i+1, j, depth+1)
dfs(rooms, i-1, j, depth+1)
dfs(rooms, i, j+1, depth+1)
dfs(rooms, i, j-1, depth+1)
"""
Histogram function.
Histogram is an accurate representation of the distribution of numerical data.
It is an estimate of the probability distribution of a continuous variable.
https://en.wikipedia.org/wiki/Histogram
Example:
list_1 = [3, 3, 2, 1]
:return {1: 1, 2: 1, 3: 2}
list_2 = [2, 3, 5, 5, 5, 6, 4, 3, 7]
:return {2: 1, 3: 2, 4: 1, 5: 3, 6: 1, 7: 1}
"""
def get_histogram(input_list: list) -> dict:
"""
Get histogram representation
:param input_list: list with different and unordered values
:return histogram: dict with histogram of input_list
"""
# Create dict to store histogram
histogram = {}
# For each list value, add one to the respective histogram dict position
for i in input_list:
histogram[i] = histogram.get(i, 0) + 1
return histogram
"""
Say you have an array for which the ith element
is the price of a given stock on day i.
If you were only permitted to complete at most one transaction
(ie, buy one and sell one share of the stock),
design an algorithm to find the maximum profit.
Example 1:
Input: [7, 1, 5, 3, 6, 4]
Output: 5
max. difference = 6-1 = 5
(not 7-1 = 6, as selling price needs to be larger than buying price)
Example 2:
Input: [7, 6, 4, 3, 1]
Output: 0
In this case, no transaction is done, i.e. max profit = 0.
"""
# O(n^2) time
def max_profit_naive(prices):
"""
:type prices: List[int]
:rtype: int
"""
max_so_far = 0
for i in range(0, len(prices) - 1):
for j in range(i + 1, len(prices)):
max_so_far = max(max_so_far, prices[j] - prices[i])
return max_so_far
# O(n) time
def max_profit_optimized(prices):
"""
input: [7, 1, 5, 3, 6, 4]
diff : [X, -6, 4, -2, 3, -2]
:type prices: List[int]
:rtype: int
"""
cur_max, max_so_far = 0, 0
for i in range(1, len(prices)):
cur_max = max(0, cur_max + prices[i] - prices[i-1])
max_so_far = max(max_so_far, cur_max)
return max_so_far
"""
You are climbing a stair case.
It takes n steps to reach to the top.
Each time you can either climb 1 or 2 steps.
In how many distinct ways can you climb to the top?
Note: Given n will be a positive integer.
"""
# O(n) space
def climb_stairs(n):
"""
:type n: int
:rtype: int
"""
arr = [1, 1]
for _ in range(1, n):
arr.append(arr[-1] + arr[-2])
return arr[-1]
# the above function can be optimized as:
# O(1) space
def climb_stairs_optimized(n):
a = b = 1
for _ in range(n):
a, b = b, a + b
return a
"""
Problem
Given a value n, if we want to make change for N cents, and we have infinite supply of each of
coins = {S1, S2, .. , Sm} valued coins, how many ways can we make the change?
The order of coins doesn't matter.
For example, for n = 4 and coins = [1, 2, 3], there are four solutions:
[1, 1, 1, 1], [1, 1, 2], [2, 2], [1, 3].
So output should be 4.
For n = 10 and coins = [2, 5, 3, 6], there are five solutions:
[2, 2, 2, 2, 2], [2, 2, 3, 3], [2, 2, 6], [2, 3, 5] and [5, 5].
So the output should be 5.
Time complexity: O(n * m) where n is the value and m is the number of coins
Space complexity: O(n)
"""
def count(coins, n):
# initialize dp array and set base case as 1
dp = [1] + [0] * n
# fill dp in a bottom up manner
for coin in coins:
for i in range(coin, n+1):
dp[i] += dp[i-coin]
return dp[n]
"""
Given an integer array with all positive numbers and no duplicates,
find the number of possible combinations that
add up to a positive integer target.
Example:
nums = [1, 2, 3]
target = 4
The possible combination ways are:
(1, 1, 1, 1)
(1, 1, 2)
(1, 2, 1)
(1, 3)
(2, 1, 1)
(2, 2)
(3, 1)
Note that different sequences are counted as different combinations.
Therefore the output is 7.
Follow up:
What if negative numbers are allowed in the given array?
How does it change the problem?
What limitation we need to add to the question to allow negative numbers?
"""
dp = None
def helper_topdown(nums, target):
global dp
if dp[target] != -1:
return dp[target]
res = 0
for i in range(0, len(nums)):
if target >= nums[i]:
res += helper_topdown(nums, target - nums[i])
dp[target] = res
return res
def combination_sum_topdown(nums, target):
global dp
dp = [-1] * (target + 1)
dp[0] = 1
return helper_topdown(nums, target)
# EDIT: The above solution is top-down. How about a bottom-up one?
def combination_sum_bottom_up(nums, target):
comb = [0] * (target + 1)
comb[0] = 1
for i in range(0, len(comb)):
for j in range(len(nums)):
if i - nums[j] >= 0:
comb[i] += comb[i - nums[j]]
return comb[target]
"""
You are given K eggs, and you have access to a building with N floors
from 1 to N. Each egg is identical in function, and if an egg breaks,
you cannot drop it again. You know that there exists a floor F with
0 <= F <= N such that any egg dropped at a floor higher than F will
break, and any egg dropped at or below floor F will not break.
Each move, you may take an egg (if you have an unbroken one) and drop
it from any floor X (with 1 <= X <= N). Your goal is to know with
certainty what the value of F is. What is the minimum number of moves
that you need to know with certainty what F is, regardless of the
initial value of F?
Example:
Input: K = 1, N = 2
Output: 2
Explanation:
Drop the egg from floor 1. If it breaks, we know with certainty that F = 0.
Otherwise, drop the egg from floor 2. If it breaks, we know with
certainty that F = 1.
If it didn't break, then we know with certainty F = 2.
Hence, we needed 2 moves in the worst case to know what F is with certainty.
"""
# A Dynamic Programming based Python Program for the Egg Dropping Puzzle
INT_MAX = 32767
def egg_drop(n, k):
# A 2D table where entery eggFloor[i][j] will represent minimum
# number of trials needed for i eggs and j floors.
egg_floor = [[0 for x in range(k+1)] for x in range(n+1)]
# We need one trial for one floor and 0 trials for 0 floors
for i in range(1, n+1):
egg_floor[i][1] = 1
egg_floor[i][0] = 0
# We always need j trials for one egg and j floors.
for j in range(1, k+1):
egg_floor[1][j] = j
# Fill rest of the entries in table using optimal substructure
# property
for i in range(2, n+1):
for j in range(2, k+1):
egg_floor[i][j] = INT_MAX
for x in range(1, j+1):
res = 1 + max(egg_floor[i-1][x-1], egg_floor[i][j-x])
if res < egg_floor[i][j]:
egg_floor[i][j] = res
# eggFloor[n][k] holds the result
return egg_floor[n][k]
"""
You are a professional robber planning to rob houses along a street.
Each house has a certain amount of money stashed,
the only constraint stopping you from robbing each of them
is that adjacent houses have security system connected and
it will automatically contact the police if two adjacent houses
were broken into on the same night.
Given a list of non-negative integers representing the amount of money
of each house, determine the maximum amount of money you
can rob tonight without alerting the police.
"""
def house_robber(houses):
last, now = 0, 0
for house in houses:
last, now = now, max(last + house, now)
return now
"""
Given positive integer n, find an algorithm to find the number of non-negative number division, or descomposition.
The complexity is O(n^2).
Example 1:
Input: 4
Output: 5
Explaination:
4=4
4=3+1
4=2+2
4=2+1+1
4=1+1+1+1
Example :
Input: 7
Output: 15
Explaination:
7=7
7=6+1
7=5+2
7=5+1+1
7=4+3
7=4+2+1
7=4+1+1+1
7=3+3+1
7=3+2+2
7=3+2+1+1
7=3+1+1+1+1
7=2+2+2+1
7=2+2+1+1+1
7=2+1+1+1+1+1
7=1+1+1+1+1+1+1
"""
def int_divide(n):
arr = [[0 for i in range(n + 1)] for j in range(n + 1)]
arr[1][1] = 1
for i in range(1, n + 1):
for j in range(1, n + 1):
if i < j:
arr[i][j] = arr[i][i]
elif i == j:
arr[i][j] = 1 + arr[i][j - 1]
else:
arr[i][j] = arr[i][j - 1] + arr[i - j][j]
return arr[n][n]
# Python program for weighted job scheduling using Dynamic
# Programming and Binary Search
# Class to represent a job
class Job:
def __init__(self, start, finish, profit):
self.start = start
self.finish = finish
self.profit = profit
# A Binary Search based function to find the latest job
# (before current job) that doesn't conflict with current
# job. "index" is index of the current job. This function
# returns -1 if all jobs before index conflict with it.
# The array jobs[] is sorted in increasing order of finish
# time.
def binary_search(job, start_index):
# Initialize 'lo' and 'hi' for Binary Search
lo = 0
hi = start_index - 1
# Perform binary Search iteratively
while lo <= hi:
mid = (lo + hi) // 2
if job[mid].finish <= job[start_index].start:
if job[mid + 1].finish <= job[start_index].start:
lo = mid + 1
else:
return mid
else:
hi = mid - 1
return -1
# The main function that returns the maximum possible
# profit from given array of jobs
def schedule(job):
# Sort jobs according to finish time
job = sorted(job, key = lambda j: j.finish)
# Create an array to store solutions of subproblems. table[i]
# stores the profit for jobs till arr[i] (including arr[i])
n = len(job)
table = [0 for _ in range(n)]
table[0] = job[0].profit
# Fill entries in table[] using recursive property
for i in range(1, n):
# Find profit including the current job
incl_prof = job[i].profit
l = binary_search(job, i)
if (l != -1):
incl_prof += table[l]
# Store maximum of including and excluding
table[i] = max(incl_prof, table[i - 1])
return table[n-1]
"""
Given the capacity of the knapsack and items specified by weights and values,
return the maximum summarized value of the items that can be fit in the
knapsack.
Example:
capacity = 5, items(value, weight) = [(60, 5), (50, 3), (70, 4), (30, 2)]
result = 80 (items valued 50 and 30 can both be fit in the knapsack)
The time complexity is O(n * m) and the space complexity is O(m), where n is
the total number of items and m is the knapsack's capacity.
"""
class Item:
def __init__(self, value, weight):
self.value = value
self.weight = weight
def get_maximum_value(items, capacity):
dp = [0] * (capacity + 1)
for item in items:
for cur_weight in reversed(range(item.weight, capacity+1)):
dp[cur_weight] = max(dp[cur_weight], item.value + dp[cur_weight - item.weight])
return dp[capacity]
"""
Given an unsorted array of integers, find the length of longest increasing subsequence.
Example:
Input: [10,9,2,5,3,7,101,18]
Output: 4
Explanation: The longest increasing subsequence is [2,3,7,101], therefore the length is 4.
Time complexity:
First algorithm is O(n^2).
Second algorithm is O(nlogx) where x is the max element in the list
Third algorithm is O(nlogn)
Space complexity:
First algorithm is O(n)
Second algorithm is O(x) where x is the max element in the list
Third algorithm is O(n)
"""
def longest_increasing_subsequence(sequence):
"""
Dynamic Programming Algorithm for
counting the length of longest increasing subsequence
type sequence: list[int]
rtype: int
"""
length = len(sequence)
counts = [1 for _ in range(length)]
for i in range(1, length):
for j in range(0, i):
if sequence[i] > sequence[j]:
counts[i] = max(counts[i], counts[j] + 1)
print(counts)
return max(counts)
def longest_increasing_subsequence_optimized(sequence):
"""
Optimized dynamic programming algorithm for
couting the length of the longest increasing subsequence
using segment tree data structure to achieve better complexity
if max element is larger than 10^5 then use
longest_increasing_subsequence_optimied2() instead
type sequence: list[int]
rtype: int
"""
mx = max(sequence)
tree = [0] * (mx<<2)
def update(p, l, r, i, v):
if l == r:
tree[p] = v
return
mid = (l+r)>>1
if i <= mid:
update(p<<1, l, mid, i, v)
else:
update((p<<1)|1, mid+1, r, i, v)
tree[p] = max(tree[p<<1], tree[(p<<1)|1])
def get_max(p, l, r, s, e):
if l > e or r < s:
return 0
if l >= s and r <= e:
return tree[p]
mid = (l+r)>>1
return max(get_max(p<<1, l, mid, s, e), get_max((p<<1)|1, mid+1, r, s, e))
ans = 0
for x in sequence:
cur = get_max(1, 0, mx, 0, x-1)+1
ans = max(ans, cur)
update(1, 0, mx, x, cur)
return ans
def longest_increasing_subsequence_optimized2(sequence):
"""
Optimized dynamic programming algorithm for
counting the length of the longest increasing subsequence
using segment tree data structure to achieve better complexity
type sequence: list[int]
rtype: int
"""
n = len(sequence)
tree = [0] * (n<<2)
sorted_seq = sorted((x, -i) for i, x in enumerate(sequence))
def update(p, l, r, i, v):
if l ==r:
tree[p] = v
return
mid = (l+r)>>1
if i <= mid:
update(p<<1, l, mid, i, v)
else:
update((p<<1)|1, mid+1, r, i, v)
tree[p] = max(tree[p<<1], tree[(p<<1)|1])
def get_max(p, l, r, s, e):
if l > e or r < s:
return 0
if l >= s and r <= e:
return tree[p]
mid = (l+r)>>1
return max(get_max(p<<1, l, mid, s, e), get_max((p<<1)|1, mid+1, r, s, e))
ans = 0
for x, j in sorted_seq:
i = -j
cur = get_max(1, 0, n-1, 0, i-1)+1
ans = max(ans, cur)
update(1, 0, n-1, i, cur)
return ans
'''
Dynamic Programming
Implementation of matrix Chain Multiplication
Time Complexity: O(n^3)
Space Complexity: O(n^2)
'''
INF = float("inf")
def matrix_chain_order(array):
n=len(array)
matrix = [[0 for x in range(n)] for x in range(n)]
sol = [[0 for x in range(n)] for x in range(n)]
for chain_length in range(2,n):
for a in range(1,n-chain_length+1):
b = a+chain_length-1
matrix[a][b] = INF
for c in range(a, b):
cost = matrix[a][c] + matrix[c+1][b] + array[a-1]*array[c]*array[b]
if cost < matrix[a][b]:
matrix[a][b] = cost
sol[a][b] = c
return matrix , sol
#Print order of matrix with Ai as matrix
def print_optimal_solution(optimal_solution,i,j):
if i==j:
print("A" + str(i),end = " ")
else:
print("(",end = " ")
print_optimal_solution(optimal_solution,i,optimal_solution[i][j])
print_optimal_solution(optimal_solution,optimal_solution[i][j]+1,j)
print(")",end = " ")
def main():
array=[30,35,15,5,10,20,25]
n=len(array)
#Size of matrix created from above array will be
# 30*35 35*15 15*5 5*10 10*20 20*25
matrix , optimal_solution = matrix_chain_order(array)
print("No. of Operation required: "+str((matrix[1][n-1])))
print_optimal_solution(optimal_solution,1,n-1)
if __name__ == '__main__':
main()
"""
Find the contiguous subarray within an array
(containing at least one number) which has the largest product.
For example, given the array [2,3,-2,4],
the contiguous subarray [2,3] has the largest product = 6.
"""
from functools import reduce
def max_product(nums):
"""
:type nums: List[int]
:rtype: int
"""
lmin = lmax = gmax = nums[0]
for i in range(len(nums)):
t1 = nums[i] * lmax
t2 = nums[i] * lmin
lmax = max(max(t1, t2), nums[i])
lmin = min(min(t1, t2), nums[i])
gmax = max(gmax, lmax)
'''
Another approach that would print max product and the subarray
Examples:
subarray_with_max_product([2,3,6,-1,-1,9,5])
#=> max_product_so_far: 45, [-1, -1, 9, 5]
subarray_with_max_product([-2,-3,6,0,-7,-5])
#=> max_product_so_far: 36, [-2, -3, 6]
subarray_with_max_product([-4,-3,-2,-1])
#=> max_product_so_far: 24, [-4, -3, -2, -1]
subarray_with_max_product([-3,0,1])
#=> max_product_so_far: 1, [1]
'''
def subarray_with_max_product(arr):
''' arr is list of positive/negative numbers '''
l = len(arr)
product_so_far = max_product_end = 1
max_start_i = 0
so_far_start_i = so_far_end_i = 0
all_negative_flag = True
for i in range(l):
max_product_end *= arr[i]
if arr[i] > 0:
all_negative_flag = False
if max_product_end <= 0:
max_product_end = arr[i]
max_start_i = i
if product_so_far <= max_product_end:
product_so_far = max_product_end
so_far_end_i = i
so_far_start_i = max_start_i
if all_negative_flag:
print("max_product_so_far: %s, %s" %
(reduce(lambda x, y: x * y, arr), arr))
else:
print("max_product_so_far: %s, %s" %
(product_so_far, arr[so_far_start_i:so_far_end_i + 1]))
def max_subarray(array):
max_so_far = max_now = array[0]
for i in range(1, len(array)):
max_now = max(array[i], max_now + array[i])
max_so_far = max(max_so_far, max_now)
return max_so_far
a = [1, 2, -3, 4, 5, -7, 23]
print(a)
print(max_subarray(a))
"""
author @goswami-rahul
To find minimum cost path
from station 0 to station N-1,
where cost of moving from ith station to jth station is given as:
Matrix of size (N x N)
where Matrix[i][j] denotes the cost of moving from
station i --> station j for i < j
NOTE that values where Matrix[i][j] and i > j does not
mean anything, and hence represented by -1 or INF
For the input below (cost matrix),
Minimum cost is obtained as from { 0 --> 1 --> 3}
= cost[0][1] + cost[1][3] = 65
the Output will be:
The Minimum cost to reach station 4 is 65
Time Complexity: O(n^2)
Space Complexity: O(n)
"""
INF = float("inf")
def min_cost(cost):
n = len(cost)
# dist[i] stores minimum cost from 0 --> i.
dist = [INF] * n
dist[0] = 0 # cost from 0 --> 0 is zero.
for i in range(n):
for j in range(i+1,n):
dist[j] = min(dist[j], dist[i] + cost[i][j])
return dist[n-1]
if __name__ == '__main__':
cost = [ [ 0, 15, 80, 90], # cost[i][j] is the cost of
[-1, 0, 40, 50], # going from i --> j
[-1, -1, 0, 70],
[-1, -1, -1, 0] ] # cost[i][j] = -1 for i > j
total_len = len(cost)
mcost = min_cost(cost)
assert mcost == 65
print("The Minimum cost to reach station %d is %d" % (total_len, mcost))
"""
A message containing letters from A-Z is being
encoded to numbers using the following mapping:
'A' -> 1
'B' -> 2
...
'Z' -> 26
Given an encoded message containing digits,
determine the total number of ways to decode it.
For example,
Given encoded message "12",
it could be decoded as "AB" (1 2) or "L" (12).
The number of ways decoding "12" is 2.
"""
def num_decodings(s):
"""
:type s: str
:rtype: int
"""
if not s or s[0] == "0":
return 0
wo_last, wo_last_two = 1, 1
for i in range(1, len(s)):
x = wo_last if s[i] != "0" else 0
y = wo_last_two if int(s[i-1:i+1]) < 27 and s[i-1] != "0" else 0
wo_last_two = wo_last
wo_last = x+y
return wo_last
def num_decodings2(s):
if not s or s.startswith('0'):
return 0
stack = [1, 1]
for i in range(1, len(s)):
if s[i] == '0':
if s[i-1] == '0' or s[i-1] > '2':
# only '10', '20' is valid
return 0
stack.append(stack[-2])
elif 9 < int(s[i-1:i+1]) < 27:
# '01 - 09' is not allowed
stack.append(stack[-2]+stack[-1])
else:
# other case '01, 09, 27'
stack.append(stack[-1])
return stack[-1]
"""
Implement regular expression matching with support for '.' and '*'.
'.' Matches any single character.
'*' Matches zero or more of the preceding element.
The matching should cover the entire input string (not partial).
The function prototype should be:
bool is_match(const char *s, const char *p)
Some examples:
is_match("aa","a") → false
is_match("aa","aa") → true
is_match("aaa","aa") → false
is_match("aa", "a*") → true
is_match("aa", ".*") → true
is_match("ab", ".*") → true
is_match("aab", "c*a*b") → true
"""
import unittest
class Solution(object):
def is_match(self, s, p):
m, n = len(s) + 1, len(p) + 1
matches = [[False] * n for _ in range(m)]
# Match empty string with empty pattern
matches[0][0] = True
# Match empty string with .*
for i, element in enumerate(p[1:], 2):
matches[0][i] = matches[0][i - 2] and element == '*'
for i, ss in enumerate(s, 1):
for j, pp in enumerate(p, 1):
if pp != '*':
# The previous character has matched and the current one
# has to be matched. Two possible matches: the same or .
matches[i][j] = matches[i - 1][j - 1] and \
(ss == pp or pp == '.')
else:
# Horizontal look up [j - 2].
# Not use the character before *.
matches[i][j] |= matches[i][j - 2]
# Vertical look up [i - 1].
# Use at least one character before *.
# p a b *
# s 1 0 0 0
# a 0 1 0 1
# b 0 0 1 1
# b 0 0 0 ?
if ss == p[j - 2] or p[j - 2] == '.':
matches[i][j] |= matches[i - 1][j]
return matches[-1][-1]
class TestSolution(unittest.TestCase):
def test_none_0(self):
s = ""
p = ""
self.assertTrue(Solution().is_match(s, p))
def test_none_1(self):
s = ""
p = "a"
self.assertFalse(Solution().is_match(s, p))
def test_no_symbol_equal(self):
s = "abcd"
p = "abcd"
self.assertTrue(Solution().is_match(s, p))
def test_no_symbol_not_equal_0(self):
s = "abcd"
p = "efgh"
self.assertFalse(Solution().is_match(s, p))
def test_no_symbol_not_equal_1(self):
s = "ab"
p = "abb"
self.assertFalse(Solution().is_match(s, p))
def test_symbol_0(self):
s = ""
p = "a*"
self.assertTrue(Solution().is_match(s, p))
def test_symbol_1(self):
s = "a"
p = "ab*"
self.assertTrue(Solution().is_match(s, p))
def test_symbol_2(self):
# E.g.
# s a b b
# p 1 0 0 0
# a 0 1 0 0
# b 0 0 1 0
# * 0 1 1 1
s = "abb"
p = "ab*"
self.assertTrue(Solution().is_match(s, p))
if __name__ == "__main__":
unittest.main()
# A Dynamic Programming solution for Rod cutting problem
INT_MIN = -32767
# Returns the best obtainable price for a rod of length n and
# price[] as prices of different pieces
def cut_rod(price):
n = len(price)
val = [0]*(n+1)
# Build the table val[] in bottom up manner and return
# the last entry from the table
for i in range(1, n+1):
max_val = INT_MIN
for j in range(i):
max_val = max(max_val, price[j] + val[i-j-1])
val[i] = max_val
return val[n]
# Driver program to test above functions
arr = [1, 5, 8, 9, 10, 17, 17, 20]
print("Maximum Obtainable Value is " + str(cut_rod(arr)))
# This code is contributed by Bhavya Jain
"""
Given a non-empty string s and a dictionary wordDict
containing a list of non-empty words,
determine if s can be segmented into a space-separated
sequence of one or more dictionary words.
You may assume the dictionary does not contain duplicate words.
For example, given
s = "leetcode",
dict = ["leet", "code"].
Return true because "leetcode" can be segmented as "leet code".
"""
"""
s = abc word_dict = ["a","bc"]
True False False False
"""
# TC: O(N^2) SC: O(N)
def word_break(s, word_dict):
"""
:type s: str
:type word_dict: Set[str]
:rtype: bool
"""
dp = [False] * (len(s)+1)
dp[0] = True
for i in range(1, len(s)+1):
for j in range(0, i):
if dp[j] and s[j:i] in word_dict:
dp[i] = True
break
return dp[-1]
if __name__ == "__main__":
s = "keonkim"
dic = ["keon", "kim"]
print(word_break(s, dic))
'''
In mathematics, the Fibonacci numbers, commonly denoted Fn, form a sequence, called the Fibonacci sequence,
such that each number is the sum of the two preceding ones, starting from 0 and 1.
That is,
F0=0 , F1=1
and
Fn= F(n-1) + F(n-2)
The Fibonacci numbers are the numbers in the following integer sequence.
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, …….
In mathematical terms, the sequence Fn of Fibonacci numbers is defined by the recurrence relation
Here, given a number n, print n-th Fibonacci Number.
'''
def fib_recursive(n):
"""[summary]
Computes the n-th fibonacci number recursive.
Problem: This implementation is very slow.
approximate O(2^n)
Arguments:
n {[int]} -- [description]
Returns:
[int] -- [description]
"""
# precondition
assert n >= 0, 'n must be a positive integer'
if n <= 1:
return n
else:
return fib_recursive(n-1) + fib_recursive(n-2)
# print(fib_recursive(35)) # => 9227465 (slow)
def fib_list(n):
"""[summary]
This algorithm computes the n-th fibbonacci number
very quick. approximate O(n)
The algorithm use dynamic programming.
Arguments:
n {[int]} -- [description]
Returns:
[int] -- [description]
"""
# precondition
assert n >= 0, 'n must be a positive integer'
list_results = [0, 1]
for i in range(2, n+1):
list_results.append(list_results[i-1] + list_results[i-2])
return list_results[n]
# print(fib_list(100)) # => 354224848179261915075
def fib_iter(n):
"""[summary]
Works iterative approximate O(n)
Arguments:
n {[int]} -- [description]
Returns:
[int] -- [description]
"""
# precondition
assert n >= 0, 'n must be positive integer'
fib_1 = 0
fib_2 = 1
sum = 0
if n <= 1:
return n
for _ in range(n-1):
sum = fib_1 + fib_2
fib_1 = fib_2
fib_2 = sum
return sum
# print(fib_iter(100)) # => 354224848179261915075
"""
Hosoya triangle (originally Fibonacci triangle) is a triangular arrangement
of numbers, where if you take any number it is the sum of 2 numbers above.
First line is always 1, and second line is always {1 1}.
This printHosoya function takes argument n which is the height of the triangle
(number of lines).
For example:
printHosoya( 6 ) would return:
1
1 1
2 1 2
3 2 2 3
5 3 4 3 5
8 5 6 6 5 8
The complexity is O(n^3).
"""
def hosoya(n, m):
if ((n == 0 and m == 0) or (n == 1 and m == 0) or
(n == 1 and m == 1) or (n == 2 and m == 1)):
return 1
if n > m:
return hosoya(n - 1, m) + hosoya(n - 2, m)
elif m == n:
return hosoya(n - 1, m - 1) + hosoya(n - 2, m - 2)
else:
return 0
def print_hosoya(n):
for i in range(n):
for j in range(i + 1):
print(hosoya(i, j) , end = " ")
print ("\n", end = "")
def hosoya_testing(n):
x = []
for i in range(n):
for j in range(i + 1):
x.append(hosoya(i, j))
return x
"""
Hosoya triangle (originally Fibonacci triangle) is a triangular arrangement
of numbers, where if you take any number it is the sum of 2 numbers above.
First line is always 1, and second line is always {1 1}.
This printHosoya function takes argument n which is the height of the triangle
(number of lines).
For example:
printHosoya( 6 ) would return:
1
1 1
2 1 2
3 2 2 3
5 3 4 3 5
8 5 6 6 5 8
The complexity is O(n^3).
"""
def hosoya(n, m):
if ((n == 0 and m == 0) or (n == 1 and m == 0) or
(n == 1 and m == 1) or (n == 2 and m == 1)):
return 1
if n > m:
return hosoya(n - 1, m) + hosoya(n - 2, m)
elif m == n:
return hosoya(n - 1, m - 1) + hosoya(n - 2, m - 2)
else:
return 0
def print_hosoya(n):
for i in range(n):
for j in range(i + 1):
print(hosoya(i, j) , end = " ")
print ("\n", end = "")
def hosoya_testing(n):
x = []
for i in range(n):
for j in range(i + 1):
x.append(hosoya(i, j))
return x
"""
An even number of trees are left along one side of a country road. You've been assigned the job to
plant these trees at an even interval on both sides of the road. The length L and width W of the road
are variable, and a pair of trees must be planted at the beginning (at 0) and at the end (at L) of
the road. Only one tree can be moved at a time. The goal is to calculate the lowest amount of
distance that the trees have to be moved before they are all in a valid position.
"""
from math import sqrt
import sys
def planting_trees(trees, L, W):
"""
Returns the minimum distance that trees have to be moved before they are all in a valid state.
Parameters:
tree (list<int>): A sorted list of integers with all trees' position along the road.
L (int): An integer with the length of the road.
W (int): An integer with the width of the road.
Returns:
A float number with the total distance trees have been moved.
"""
trees = [0] + trees
n_pairs = int(len(trees)/2)
space_between_pairs = L/(n_pairs-1)
target_locations = [location*space_between_pairs for location in range(n_pairs)]
cmatrix = [[0 for _ in range(n_pairs+1)] for _ in range(n_pairs+1)]
for ri in range(1, n_pairs+1):
cmatrix[ri][0] = cmatrix[ri-1][0] + sqrt(W + abs(trees[ri]-target_locations[ri-1])**2)
for li in range(1, n_pairs+1):
cmatrix[0][li] = cmatrix[0][li-1] + abs(trees[li]-target_locations[li-1])
for ri in range(1, n_pairs+1):
for li in range(1, n_pairs+1):
cmatrix[ri][li] = min(
cmatrix[ri-1][li] + sqrt(W + (trees[li + ri]-target_locations[ri-1])**2),
cmatrix[ri][li-1] + abs(trees[li + ri]-target_locations[li-1])
)
return cmatrix[n_pairs][n_pairs]
"""
Bipartite graph is a graph whose vertices can be divided into two disjoint and independent sets.
(https://en.wikipedia.org/wiki/Bipartite_graph)
Time complexity is O(|E|)
Space complexity is O(|V|)
"""
def check_bipartite(adj_list):
V = len(adj_list)
# Divide vertexes in the graph into set_type 1 and 2
# Initialize all set_types as -1
set_type = [-1 for v in range(V)]
set_type[0] = 0
q = [0]
while q:
v = q.pop(0)
# If there is a self-loop, it cannot be bipartite
if adj_list[v][v]:
return False
for u in range(V):
if adj_list[v][u]:
if set_type[u] == set_type[v]:
return False
elif set_type[u] == -1:
# set type of u opposite of v
set_type[u] = 1 - set_type[v]
q.append(u)
return True
from collections import defaultdict
class Graph:
def __init__(self,v):
self.v = v
self.graph = defaultdict(list)
def add_edge(self,u,v):
self.graph[u].append(v)
def dfs(self):
visited = [False] * self.v
self.dfs_util(0,visited)
if visited == [True]*self.v:
return True
return False
def dfs_util(self,i,visited):
visited[i] = True
for u in self.graph[i]:
if not(visited[u]):
self.dfs_util(u,visited)
def reverse_graph(self):
g = Graph(self.v)
for i in range(len(self.graph)):
for j in self.graph[i]:
g.add_edge(j,i)
return g
def is_sc(self):
if self.dfs():
gr = self.reverse_graph()
if gr.dfs():
return True
return False
g1 = Graph(5)
g1.add_edge(0, 1)
g1.add_edge(1, 2)
g1.add_edge(2, 3)
g1.add_edge(3, 0)
g1.add_edge(2, 4)
g1.add_edge(4, 2)
print ("Yes") if g1.is_sc() else print("No")
g2 = Graph(4)
g2.add_edge(0, 1)
g2.add_edge(1, 2)
g2.add_edge(2, 3)
print ("Yes") if g2.is_sc() else print("No")
"""
Clone an undirected graph. Each node in the graph contains a label and a list
of its neighbors.
OJ's undirected graph serialization:
Nodes are labeled uniquely.
We use # as a separator for each node, and , as a separator for node label and
each neighbor of the node.
As an example, consider the serialized graph {0,1,2#1,2#2,2}.
The graph has a total of three nodes, and therefore contains three parts as
separated by #.
First node is labeled as 0. Connect node 0 to both nodes 1 and 2.
Second node is labeled as 1. Connect node 1 to node 2.
Third node is labeled as 2. Connect node 2 to node 2 (itself), thus forming a
self-cycle.
Visually, the graph looks like the following:
1
/ \
/ \
0 --- 2
/ \
\_/
"""
import collections
# Definition for a undirected graph node
class UndirectedGraphNode:
def __init__(self, x):
self.label = x
self.neighbors = []
# BFS
def clone_graph1(node):
if not node:
return
node_copy = UndirectedGraphNode(node.label)
dic = {node: node_copy}
queue = collections.deque([node])
while queue:
node = queue.popleft()
for neighbor in node.neighbors:
if neighbor not in dic: # neighbor is not visited
neighbor_copy = UndirectedGraphNode(neighbor.label)
dic[neighbor] = neighbor_copy
dic[node].neighbors.append(neighbor_copy)
queue.append(neighbor)
else:
dic[node].neighbors.append(dic[neighbor])
return node_copy
# DFS iteratively
def clone_graph2(node):
if not node:
return
node_copy = UndirectedGraphNode(node.label)
dic = {node: node_copy}
stack = [node]
while stack:
node = stack.pop()
for neighbor in node.neighbors:
if neighbor not in dic:
neighbor_copy = UndirectedGraphNode(neighbor.label)
dic[neighbor] = neighbor_copy
dic[node].neighbors.append(neighbor_copy)
stack.append(neighbor)
else:
dic[node].neighbors.append(dic[neighbor])
return node_copy
# DFS recursively
def clone_graph(node):
if not node:
return
node_copy = UndirectedGraphNode(node.label)
dic = {node: node_copy}
dfs(node, dic)
return node_copy
def dfs(node, dic):
for neighbor in node.neighbors:
if neighbor not in dic:
neighbor_copy = UndirectedGraphNode(neighbor.label)
dic[neighbor] = neighbor_copy
dic[node].neighbors.append(neighbor_copy)
dfs(neighbor, dic)
else:
dic[node].neighbors.append(dic[neighbor])
"""
Given a directed graph, check whether it contains a cycle.
Real-life scenario: deadlock detection in a system. Processes may be
represented by vertices, then and an edge A -> B could mean that process A is
waiting for B to release its lock on a resource.
"""
from enum import Enum
class TraversalState(Enum):
WHITE = 0
GRAY = 1
BLACK = 2
example_graph_with_cycle = {'A': ['B', 'C'],
'B': ['D'],
'C': ['F'],
'D': ['E', 'F'],
'E': ['B'],
'F': []}
example_graph_without_cycle = {'A': ['B', 'C'],
'B': ['D', 'E'],
'C': ['F'],
'D': ['E'],
'E': [],
'F': []}
def is_in_cycle(graph, traversal_states, vertex):
if traversal_states[vertex] == TraversalState.GRAY:
return True
traversal_states[vertex] = TraversalState.GRAY
for neighbor in graph[vertex]:
if is_in_cycle(graph, traversal_states, neighbor):
return True
traversal_states[vertex] = TraversalState.BLACK
return False
def contains_cycle(graph):
traversal_states = {vertex: TraversalState.WHITE for vertex in graph}
for vertex, state in traversal_states.items():
if (state == TraversalState.WHITE and
is_in_cycle(graph, traversal_states, vertex)):
return True
return False
print(contains_cycle(example_graph_with_cycle))
print(contains_cycle(example_graph_without_cycle))
# takes dict of sets
# each key is a vertex
# value is set of all edges connected to vertex
# returns list of lists (each sub list is a maximal clique)
# implementation of the basic algorithm described in:
# Bron, Coen; Kerbosch, Joep (1973), "Algorithm 457: finding all cliques of an undirected graph",
def find_all_cliques(edges):
def expand_clique(candidates, nays):
nonlocal compsub
if not candidates and not nays:
nonlocal solutions
solutions.append(compsub.copy())
else:
for selected in candidates.copy():
candidates.remove(selected)
candidates_temp = get_connected(selected, candidates)
nays_temp = get_connected(selected, nays)
compsub.append(selected)
expand_clique(candidates_temp, nays_temp)
nays.add(compsub.pop())
def get_connected(vertex, old_set):
new_set = set()
for neighbor in edges[str(vertex)]:
if neighbor in old_set:
new_set.add(neighbor)
return new_set
compsub = []
solutions = []
possibles = set(edges.keys())
expand_clique(possibles, set())
return solutions
myGraph = {'A': ['B', 'C'],
'B': ['C', 'D'],
'C': ['D', 'F'],
'D': ['C'],
'E': ['F'],
'F': ['C']}
# find path from start to end using recursion with backtracking
def find_path(graph, start, end, path=[]):
path = path + [start]
if (start == end):
return path
if not start in graph:
return None
for node in graph[start]:
if node not in path:
newpath = find_path(graph, node, end, path)
return newpath
return None
# find all path
def find_all_path(graph, start, end, path=[]):
path = path + [start]
if (start == end):
return [path]
if not start in graph:
return None
paths = []
for node in graph[start]:
if node not in path:
newpaths = find_all_path(graph, node, end, path)
for newpath in newpaths:
paths.append(newpath)
return paths
def find_shortest_path(graph, start, end, path=[]):
path = path + [start]
if start == end:
return path
if start not in graph:
return None
shortest = None
for node in graph[start]:
if node not in path:
newpath = find_shortest_path(graph, node, end, path)
if newpath:
if not shortest or len(newpath) < len(shortest):
shortest = newpath
return shortest
print(find_all_path(myGraph, 'A', 'F'))
# print(find_shortest_path(myGraph, 'A', 'D'))
"""
These are classes to represent a Graph and its elements.
It can be shared across graph algorithms.
"""
class Node(object):
def __init__(self, name):
self.name = name
@staticmethod
def get_name(obj):
if isinstance(obj, Node):
return obj.name
elif isinstance(obj, str):
return obj
return''
def __eq__(self, obj):
return self.name == self.get_name(obj)
def __repr__(self):
return self.name
def __hash__(self):
return hash(self.name)
def __ne__(self, obj):
return self.name != self.get_name(obj)
def __lt__(self, obj):
return self.name < self.get_name(obj)
def __le__(self, obj):
return self.name <= self.get_name(obj)
def __gt__(self, obj):
return self.name > self.get_name(obj)
def __ge__(self, obj):
return self.name >= self.get_name(obj)
def __bool__(self):
return self.name
class DirectedEdge(object):
def __init__(self, node_from, node_to):
self.nf = node_from
self.nt = node_to
def __eq__(self, obj):
if isinstance(obj, DirectedEdge):
return obj.nf == self.nf and obj.nt == self.nt
return False
def __repr__(self):
return '({0} -> {1})'.format(self.nf, self.nt)
class DirectedGraph(object):
def __init__(self, load_dict={}):
self.nodes = []
self.edges = []
self.adjmt = {}
if load_dict and type(load_dict) == dict:
for v in load_dict:
node_from = self.add_node(v)
self.adjmt[node_from] = []
for w in load_dict[v]:
node_to = self.add_node(w)
self.adjmt[node_from].append(node_to)
self.add_edge(v, w)
def add_node(self, node_name):
try:
return self.nodes[self.nodes.index(node_name)]
except ValueError:
node = Node(node_name)
self.nodes.append(node)
return node
def add_edge(self, node_name_from, node_name_to):
try:
node_from = self.nodes[self.nodes.index(node_name_from)]
node_to = self.nodes[self.nodes.index(node_name_to)]
self.edges.append(DirectedEdge(node_from, node_to))
except ValueError:
pass
class Graph:
def __init__(self, vertices):
# No. of vertices
self.V = vertices
# default dictionary to store graph
self.graph = {}
# To store transitive closure
self.tc = [[0 for j in range(self.V)] for i in range(self.V)]
# function to add an edge to graph
def add_edge(self, u, v):
if u in self.graph:
self.graph[u].append(v)
else:
self.graph[u] = [v]
#g = Graph(4)
#g.add_edge(0, 1)
#g.add_edge(0, 2)
#g.add_edge(1, 2)
#g.add_edge(2, 0)
#g.add_edge(2, 3)
#g.add_edge(3, 3)
#Dijkstra's single source shortest path algorithm
class Dijkstra():
def __init__(self, vertices):
self.vertices = vertices
self.graph = [[0 for column in range(vertices)] for row in range(vertices)]
def min_distance(self, dist, min_dist_set):
min_dist = float("inf")
for v in range(self.vertices):
if dist[v] < min_dist and min_dist_set[v] == False:
min_dist = dist[v]
min_index = v
return min_index
def dijkstra(self, src):
dist = [float("inf")] * self.vertices
dist[src] = 0
min_dist_set = [False] * self.vertices
for count in range(self.vertices):
#minimum distance vertex that is not processed
u = self.min_distance(dist, min_dist_set)
#put minimum distance vertex in shortest tree
min_dist_set[u] = True
#Update dist value of the adjacent vertices
for v in range(self.vertices):
if self.graph[u][v] > 0 and min_dist_set[v] == False and dist[v] > dist[u] + self.graph[u][v]:
dist[v] = dist[u] + self.graph[u][v]
return dist
import random
my_chain = {
'A': {'A': 0.6,
'E': 0.4},
'E': {'A': 0.7,
'E': 0.3}
}
def __choose_state(state_map):
choice = random.random()
probability_reached = 0
for state, probability in state_map.items():
probability_reached += probability
if probability_reached > choice:
return state
def next_state(chain, current_state):
next_state_map = chain.get(current_state)
next_state = __choose_state(next_state_map)
return next_state
def iterating_markov_chain(chain, state):
while True:
state = next_state(chain, state)
yield state
Download Details:
Author: keon
Source Code: https://github.com/keon/algorithms
License: MIT
#datastructures #algorithms #python
1670346000
Requirement is to create Modern pages with content, which includes images and text.
The Content is in SharePoint List. The pages are created from a Page Template.
To get Text part from Page template, use below PowerShell,
#get page textpart instance id
$parts=Get-PnPPageComponent -Page <pagename.aspx>
Execute the below PowerShell to create pages with HTML content from SharePoint List.
$logFile = "Logs\LogFile.log"
Start - Transcript - Path $logFile - Append
#Variables
$libName = "Site Pages"
$siteURL = "https://tenant.sharepoint.com/"
$contentType = "Group and Division Page"
$listname = "Content"
$sectionCategoy = "Our organisation"
#End
Try {
#Connect to PnP Online
$connection = Connect - PnPOnline - Url $siteURL - UseWebLogin - ReturnConnection - WarningAction Ignore
#Get items from Content list
$items = Get - PnPListItem - List $listName - PageSize 100
foreach($item in $items) {
if ($null - ne $item["Title"] - and $null - ne $item["Content"]) {
#Get Page webparts instance Id
#$parts = Get - PnPPageComponent - Page PageTemplate.aspx
# load the page template
$template = Get - PnPClientSidePage - Identity "Templates/Division-page-template"
#Get page name
$fullFileName = $item["Title"].Replace(" ", "_") + ".aspx"
#Create fileURL
$fileURL = $siteURL + $libName + "/" + $fullFileName
# save a new SharePoint Page based on the Page Template
$template.Save($fullFileName)
$page = Get - PnPPage - Identity $fullFileName
$htmlToInject = $item["Content"]
$htmlToInject = $htmlToInject.TrimStart('{"Html":"').TrimEnd('"}') - replace([regex]::Escape('\n')), '' - replace([regex]::Escape('<a href=\')),' < a href = ' -replace ([regex]:: Escape('\
">')),'" > ' -replace ([regex]::Escape(' & bull; % 09 ')),'
' -replace '
https:
/*','https://'
#Set PnP Page Text
Set-PnPPageTextPart -Page $page -InstanceId "9fab3ce6-0638-4008-a9b9-cf2b784245b5" -Text $htmlToInject
#publish page
Set-PnPPage -Identity $fullFileName -Title $item["Title"] -ContentType $contentType -Publish
#get site pages library
$sitepagelist= Get-PnPList -Identity 'Site Pages'
#get page Id and page Item to update section category
$pageItem=Get-PnPListItem -List $sitepagelist -Id $page.PageId
Set-PnPListItem -Values @{"SectionCategory" = $sectionCategoy} -List $sitepagelist -Identity $pageItem
}
else
{
Write-Host "Title or Content has no value"
}
}
}
Catch {
Write-Host "Error: $($_.Exception.Message)" -Foregroundcolor Red
}
Stop-Transcript
Original article source at: https://www.c-sharpcorner.com/