0

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).

Coffee inTime
  • 231
  • 1
  • 8
  • This is pretty easy with a regex and reasonably quick. I think that if you tried hard that you could say that an FSA uses the branch and bound method but it doesn't sound all that reasonable. – Michael Salmon Aug 05 '19 at 19:33
  • I am having a bit of trouble understanding your task. It seems that you have to create a list of all possible words of length N and then remove all words with repeated sequences. If that is the case then you can take a list of correct words of length N-1, create 3 branches by adding a, b and c and then remove words that have repeats. Of course to create the N-1 list you need to create the N-2 list etc. I believe that this follows the branch and bound method. Regex's are still a good way of testing although the seem only to be supported in Objective C. – Michael Salmon Aug 07 '19 at 12:11
  • Another thing with build on N-1 strings. There are no matches in the N-1 good list which means that you only have to search for the last character at N-1 plus your branching character – Michael Salmon Aug 07 '19 at 14:30

1 Answers1

1

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

Alexandr Kolesnik
  • 1,929
  • 1
  • 17
  • 30
  • Something like this was explained to me about the solution: similar problems are solved by the method of branches and borders, this is also a special case of in-depth searches. the algorithm is pretty simple. You need to take an empty start line, call the search function after in the function we check the input line, if it is of the correct length - we are happy, we found a new word. Otherwise, you need to create a new line, add the first letter, check the correctness of the word (length) if right - go to recursion with a new word if not correct, take the next letter and so on. – Coffee inTime Aug 05 '19 at 13:13
  • Sorry, but that’s not it. The function must take the word length (N). And return the number of correct words in this length. (Which do not have duplicates of the same letter sequence) Example: abca is the right word. abab is wrong. aaaa is also wrong. abcabc is also incorrect. – Coffee inTime Aug 05 '19 at 14:12
  • abca is correct when constant = 2, abcabc is incorrect when constant = 3, how to count? N what are the rules? – Alexandr Kolesnik Aug 05 '19 at 14:17