Leetcode Q. 1528. Shuffle String - swift

Given a string s and an integer array indices of the same length.
The string s will be shuffled such that the character at the ith position moves to indices[i] in the shuffled string.
Return the shuffled string.
Input: s = "codeleet", indices = [4,5,6,7,0,2,1,3]
Output: "leetcode"
Explanation: As shown, "codeleet" becomes "leetcode" after shuffling.
class Solution {
func restoreString(_ s: String, _ indices: [Int]) -> String {
//convert the string into a hash map where all keys are Ints and the values are the Strings.
//Run a for loop through the dictionary and return the key of the value in indices.
//time complexity: O(n)
//Space complexity: O(n)
var newString = s.map{ String($0) }
var y = ""
var count = 0
var dict = [Int:String]()
var z = 0
while count < newString.count {
dict[count] = newString[count]
count += 1
}
while z < indices.count {
y.append(dict[indices[z]]!)
z += 1
}
print(dict)
return y
}
}
The first while loop creates a dictionary and the second while loop finds the values with matching keys and appends into a string. My issue is that my code is outputting two characters in the wrong location.
Input: "codeleet"
[4,5,6,7,0,2,1,3]
Output: "leetcdoe"
Can you please help me explain what I'm missing here.

Its a one to one hashing not a index based hashing which you were doing in above code below is the updated correct version of your code:-
class Solution {
func restoreString(_ s: String, _ indices: [Int]) -> String {
var newString = s.map{ String($0) }
var y = ""
var count = 0
var dict = [Int:String]()
var z = 0
while count < newString.count {
dict[indices[count]] = newString[count]
count += 1
}
while z < indices.count {
y.append(dict[z]!)
z += 1
}
print(dict)
return y
}
}

class Solution {
public String restoreString(String s, int[] indices) {
String s1="";
for(int i=0;i<s.length();i++){
for(int j=0;j<s.length();j++){
if(i==indices[j]){
s1=s1+s.charAt(j);
}
}
}return s1;
}

func restoreString(_ s: String, _ indices: [Int]) -> String {
var letters = [String]()
var result = ""
s.forEach{
letters.append(String($0))
}
for (index,value) in s.enumerated(){
letters[indices[index]] = value.description
}
result = letters.reduce("", +)
return result }

Related

Finding indices of array elements that add up to a target number. What would be a way to optimize my solution?

I'm practicing this problem
Given an array of integers nums and an integer target, return indices
of the two numbers such that they add up to target.
You may assume that each input would have exactly one solution, and
you may not use the same element twice.
You can return the answer in any order.
and came up with
class Solution {
func twoSum(_ nums: [Int], _ target: Int) -> [Int] {
var indices = [Int]()
for (firstIndex, firstNum) in nums.enumerated() {
for (secondIndex, secondNum) in nums.enumerated() {
if firstNum + secondNum == target && firstIndex != secondIndex {
indices = [firstIndex, secondIndex]
}
}
}
return indices
}
}
However, it has quadratic time complexity because of the nested for-in loops. What would be a good way to optimize this to run in linear time?
Here's an idea that results in a O(n) time ans space solution.
Have a hashtable that maps elements to their indices.
As you iterate through the input array check whether target - element is in the hashtable already. If so, return the indices of the current element and target - element in the hashtable.
If not, add current element as key and its index as value to the hashtable.
Using #user1984 comment your solution should look like this:
class Solution {
func twoSum(_ nums: [Int], _ target: Int) -> [Int] {
var indices = [Int]()
var dictionary: [Int: Int] = [:]
for (index, num) in nums.enumerated()
{
let diff = target - num
if let index2 = dictionary[diff] {
return [index2, index]
}
else {
dictionary[num] = index
}
}
return []
}
}
There are several approaches (depending on your requirements and time/space constraints)
final class Solution {
// Time Complexity: O(n * (n - 1) / 2) = O(n^2)
// Auxiliary Space: O(1)
func twoSum1(_ nums: [Int], _ target: Int) -> [Int] {
for firstIndex in nums.indices {
for secondIndex in (firstIndex + 1)..<nums.count {
if nums[firstIndex] + nums[secondIndex] == target {
return [firstIndex, secondIndex]
}
}
}
return []
}
// Time Complexity: O(n log n).
// Auxiliary Space: O(n). Can be O(1) if do in-place sort
func twoSum2(_ nums: [Int], _ target: Int) -> [Int] {
let sorted = nums.sorted()
var left = 0
var right = nums.count - 1
while left < right {
if sorted[left] + sorted[right] == target {
return [left, right]
} else if sorted[left] + sorted[right] < target {
left += 1
} else {
right -= 1
}
}
return []
}
// Time Complexity: O(n). (Amortized)
// Auxiliary Space: O(n).
func twoSum3(_ nums: [Int], _ target: Int) -> [Int] {
var differences = [Int: Int]()
for (index, element) in nums.enumerated() {
let difference = target - element
if let dIndex = differences[difference] {
return [index, dIndex]
}
differences[element] = index
}
return []
}
static func test() {
// Given
let nums = [1, 5, 4, 3, 7, 9, -3]
let target = 7
let solution = Solution()
let expectedResult = [2, 3]
// When
let result1 = solution.twoSum1(nums, target)
let result2 = solution.twoSum2(nums, target)
let result3 = solution.twoSum3(nums, target)
// Then
assert(Set(result1) == Set(expectedResult))
assert(Set(result2) == Set(expectedResult))
assert(Set(result3) == Set(expectedResult))
}
}

Prime factorization with return being a string

I am trying to solve the following coding challenge:
Given a positive number n > 1 find the prime factor decomposition of n. The result will be a string with the following form:
"(p1xxn1)(p2xxn2)...(pkxxnk)"
with the p(i) in increasing order and n(i) empty if n(i) is 1.
Example: n = 86240 should return "(2xx5)(5)(7xx2)(11)"
I believe I have figured out how to find the prime factors of a number... my problem is that I have no idea how to convert them into the form required by the question (i.e., a string where p(i) is in increasing order). I tried to convert an integer array containing the prime factors into some sort of array of tuples containing factors p and n, but I have been struggling fruitlessly for several hours.
Here is what I have so far:
func factors(_ number: Int) -> String {
var changedNumber = number
var numberArr = [Int]()
while changedNumber >= 2 {
for i in 2...changedNumber {
if changedNumber % i == 0 {
numberArr.append(i)
changedNumber /= i
break
}
}
}
}
Any insight or resources would be greatly appreciated.
func factors(_ number: Int) -> String
I think it’s a mistake to make this return the String directly. It violates the separation of responsibilities, and makes this hard to reuse.
Imagine elsewhere in a codebase that uses this function, there might be a function which tries to parse the string result of this back into an array to use it in some other way. It may sound ridiculous, but a large number of the questions we get on here are about people trying to build systems to accept silly input from other systems that they should just change instead!
Here's what I would suggest:
func primeFactorization(of value: Int) -> (factor: Int, exponent: Int) {
...
}
func format(_ primeFactors: [(factor: Int, exponent: Int)]) -> String {
return primeFactors
.map { $0.exponent == 1 ? "(\($0.factor))" : "(\($0.factor)xx\($0.exponent))" }
.joined()
}
So you can then do:
let factorization = primeFactorization(of: 86240)
// Which results in: [
// (factor: 2, exponent: 5),
// (factor: 2, exponent: 1),
// (factor: 7, exponent: 2),
// (factor: 11, exponent: 1),
// ]
// Which you can then format as this one question wants:
format(factorization) // => "(2xx5)(5)(7xx2)(11)"
For extra points, you could generify the first function into an extension on BinaryInteger, which would let you be able to write something like 86240.primeFactorization().
Just make your function group the numbers and then use each sub collection count when creating your string:
func factors(_ number: Int) -> String {
var changedNumber = number
var numberArr: [[Int]] = []
while changedNumber >= 2 {
for i in 2...changedNumber {
if changedNumber.isMultiple(of: i) {
if numberArr.last?.last == i {
numberArr[numberArr.count-1].append(i)
} else {
numberArr.append([i])
}
changedNumber /= i
break
}
}
}
return numberArr.reduce(into: "") {
if let last = $1.last {
if $1.count == 1 {
$0 += "(" + String(last) + ")"
} else {
$0 += "(" + String(last) + "xx\($1.count))"
}
}
}
}
print(factors(86240)) // (2xx5)(5)(7xx2)(11)
There's lots of ways to handle this. Here's one, off the top of my head:
Write an extension to Int that has the following functions
func isPrime() -> Bool
func nextPrime() -> Int.
First check to see if the input number n is prime. If it is, return the result as "(nxxx1)" and you're done.
Define a struct primeFactor:
struct PrimeFactor {
let value: Int
var count: Int
}
Create an array of PrimeFactors.
func primeFactorsString(of value: String) -> String {
var primeFactors = [PrimeFactor]()
var currentPrime = 1
var remainder = value
guard !value.isPrime() else { return "(\(value)xx1)" }
while remainder > 1 {
currentPrime = currentPrime.nextPrime()
if remainder % currentPrime == 0 {
let newPrimeFactor = PrimeFactor(value: currentPrime, count: 1)
remainder /= currentPrime
while remainder % currentPrime == 0 {
newPrimeFactor.count = newPrimeFactor.count + 1
remainder /= currentPrime
}
primeFactors.append(newPrimeFactor)
}
}
// Now loop through your array of primeFactors and build your output string.
return primeFactors.map { "(\($0.value)xx\($0.count))".joined()

How to solve a problem with using the method of branches and borders?

All words of the ternary language consist of only 3 letters: a, b, and c and all have a strictly specified length N. Words that do not contain two identical subsequences of letters in a row are considered correct. For example, abcacb is the correct word, and ababc is not the correct one, since the ab subsequences go there.
I tried to solve the problem with a complete enumeration of all possible combinations and a function that looked for a repeating sequence. However, this turned out to be the wrong decision. The problem needs to be solved somehow using the branch and bound method. I have absolutely no idea how this problem can be solved by this method. I would be very happy if someone provides examples or explains to me. I have already spent six days to solve this problem and am very tired.
My wrong solution:
import Foundation
func findRepetition(_ p: String) -> [String:Int] {
var repDict: [String:Int] = [:]
var p = p
while p.count != 0 {
for i in 0...p.count-1 {
repDict[String(Array(p)[0..<i]), default: 0] += 1
}
p = String(p.dropFirst())
}
return repDict
}
var correctWords = [String]()
var wrongWords = [String]()
func getRepeats(_ p: String) -> Bool {
let p = p
var a = findRepetition(p)
for i in a {
var substring = String(Array(repeating: i.key, count: 2).joined())
if p.contains(substring) {
wrongWords.append(p)
return false
}
}
correctWords.append(p)
return true
}
var counter = 0
func allLexicographicRecur (_ string: [String.Element], _ data: [String], _ last: Int, _ index: Int){
var length = string.count-1
var data = data
for i in 0...length {
data[index] = String(string[i])
if index == last {
if getRepeats(data.joined()) {
counter += 1
}
}else{
allLexicographicRecur(string, data, last, index+1)
}
}
}
func threeLanguage(_ l: Int) {
var alphabet = "abc"
var data = Array(repeating: "", count: l)
allLexicographicRecur(alphabet.sorted(), data, l-1, 0)
print("The specified word length: \(l), the number of correct words: \(counter)\n")
print("Correct words:\n\(correctWords)\n")
print("Wrong words:\n\(wrongWords)")
}
threeLanguage(3)
Example:
abca is the right word.
abab is wrong (ab).
aaaa is also wrong (a).
abcabc is also incorrect (abc).
If I correctly understood your problem, you need to separate you input string to parts N-length and check parts by your rules. Smth like this
let constant: Int = 3
extension String {
private func components(withLength length: Int) -> [String] {
return stride(from: 0, to: count, by: length).map {
let start = index(startIndex, offsetBy: $0)
let end = index(start, offsetBy: length, limitedBy: endIndex) ?? endIndex
return String(self[start ..< end])
}
}
var numberOfValidWords: Int {
var numberOfIncorrectWords = 0
let length = count - constant
let array = components(withLength: constant)
for component in array {
let computedLength = replacingOccurrences(of: component, with: "").count
if computedLength != length {
print("as is lengths are not equal, this part is met in string several times")
numberOfIncorrectWords += 1
continue
}
}
return array.count - numberOfIncorrectWords
}
}
Hope it will be helpful

How to use variable outside the loop, after initializing inside the loop?

Want to code a function that will take an array of strings named straar and an integer named k. It will return k times longest strings merged together.
code:
import UIKit
func longestConsec( strarr: [String], k: Int) -> String {
var strerr : [String] = Array()
strerr = strarr
var longest : Int
longest = 0
var longestString : String
var finalBoss : String
finalBoss = ""
for v in 1...k{
for long in strerr{
if (long.count > longest){
longest = long.count
longestString = long
}
}
finalBoss += longestString
for lang in 0...strerr.count{
if (strerr[lang] == longestString){
strerr.remove(at:lang)
}
}
}
return finalBoss
}
there are some problem with the code. The var 'longestString' needs to be initialized before being used. And in the last for loop fails because the index is mayor than the count of items. Here's the code with some corrections.
func longestConsec( strarr: [String], k: Int) -> String {
var strerr = strarr
var longest : Int
longest = 0
var longestString : String = ""
var finalBoss : String
finalBoss = ""
for _ in 1...k {
for long in strerr {
if (long.count > longest) {
longest = long.count
longestString = long
}
}
finalBoss += longestString
for lang in 1 ..< strerr.count {
if (strerr[lang] == longestString) {
strerr.remove(at:lang)
}
}
}
print("finalBoss: \(finalBoss)")
return finalBoss
}
longestConsec(strarr: ["Eleven", "Two", "Three"], k: 3)

How can I optimize this code that manipulates strings?

I am trying to come up with a faster solution to this Hackerrank problem: https://www.hackerrank.com/challenges/30-review-loop
In short, I have to separate each input string into two strings, the first one having the even index characters of the original string and the second one having odd indexes.
The number of strings to be separated are saved to the numStrings constant, the strings themselves are stored in inputString.
import Foundation
let numStrings = Int(readLine()!)!
func printEvenAndOdd(string: String) {
var firstString = ""
var secondString = ""
var stringIndex = string.index(string.startIndex, offsetBy: 0)
for index in 0..<string.characters.count {
stringIndex = string.index(string.startIndex, offsetBy: index)
if index % 2 == 0 {
firstString += String(string[stringIndex])
} else {
secondString += String(string[stringIndex])
}
}
print(firstString + " " + secondString)
}
for _ in 1...numStrings {
let inputString = readLine()!
printEvenAndOdd(string: inputString)
}
My code works, but fails the last 3 tests due to timeout. Can I make the algorithm quicker?
func index(_ i: String.Index, offsetBy n: String.IndexDistance) -> String.Index
is O(n), which means it gets slower as n increases. So the longer your string, the slower your algorithm will run.
To access the characters in O(1) time, you should just use for char in string.characters to get the characters.
If you use string.characters.enumerated(), you will get a sequence of tuples that hold the index of the character and the character itself. Then your code becomes:
func printEvenAndOdd(string: String) {
var firstString = ""
var secondString = ""
for (index, char) in string.characters.enumerated() {
if index % 2 == 0 {
firstString += String(char)
} else {
secondString += String(char)
}
}
print(firstString + " " + secondString)
}
According to the Swift String reference the index(_, offsetBy) function performs with complexity O(n) leading to a total complexity of O(n^2). The following function should perform better:
func printEvenAndOdd(string: String) {
var firstString = ""
var secondString = ""
var i = 0
for c in string.characters {
if i % 2 == 0 {
firstString += String(c)
} else {
secondString += String(c)
}
i += 1
}
print(firstString + " " + secondString)
}