JS 程序将给定的字符串沿指定方向旋转指定幅度

Posted

技术标签:

【中文标题】JS 程序将给定的字符串沿指定方向旋转指定幅度【英文标题】:JS program to rotate a given String in specified direction by specified magnitude 【发布时间】:2020-08-30 18:01:48 【问题描述】:

函数必须接受两个字符串参数:一个是要旋转的字符串,第二个字符串表示在特定方向上具有特定幅度的任意数量的旋转。第二个字符串的形式为: X a X b X c .... 其中 X 表示旋转方向,即 L 或 R. a,b,c... 是表示幅度的整数(不超过 9 个)在他们左侧的方向。

例如,如果这些是参数: ("abcde","L 3 R 2 R 4") 输出将是 YES

解释:

此处,旋转次数为 3。 应用第一次旋转 L 3 后,字符串为: 'deabc'。这里,第一个字符是 'd' 应用第二次旋转 R 2 后,字符串为: 'bcdea'。这里,第一个字符是'b' 应用第三次旋转 R 4 后,字符串为: 'cdeab'。这里,第一个字符是'c'

因此,在所有旋转之后,FIRSTCHARSTRING 字符串将是“dbc”,它是原始字符串“abcde”的子字符串的变位词。

这是我尝试过但没有得到任何结果的方法


const task18 = (str1, str2) => 
  let count;
  for (let i in str2) 
    if (str2[i] === "L") 
      let ans = str1.substring(str2[i + 1]) + str1.substring(0, str2[i + 1]);
      count = ans[0];
      return ans;
     else 
      return str1.substring(str1, str1.length - str2[i + 1]);
    
  
;

【问题讨论】:

YES 来自哪里?? 如果是字谜,那么是,否则不是 所以返回值不应该是布尔值而是字符串? 还有,输入字符串中的字符是唯一的,还是有重复的? 这是给出的唯一问题陈述。如果字谜,ans 应该是 YES,否则应该是 NO 【参考方案1】:

几个问题:

您总是在第一次迭代中退出循环(使用return)。 substring 的最后一次调用有一个字符串作为第一个参数,而需要一个数字。 count = ans[0]; 从错误的地方进行计数。将从str2 而非ans 检索。 没有尝试查找字谜是否匹配 该函数尝试返回str1 的一部分,但赋值是返回“YES”或“NO”。

最简单的部分是旋转。事实上,没有必要真正旋转str1。使用索引指向旋转后字符串的开头会更有效。

困难的部分是找出构造的字符串是否是str1 的子字符串的变位词。困难在于str1 中的某些字符可能是重复的,因此当您在重复的字母中选择错误的字符时,尝试匹配可能会失败。这可以通过使用递归和回溯来尝试在重复中使用一个字符,然后使用下一个字符来解决,直到成功或所有尝试都失败。

您可以采取一些额外的措施来改善运行时间:当旋转字符串的旋转次数超过str1 中的字符数时,您已经可以返回“NO”。

如果旋转导致使用某个字符的字符串比str1中出现的次数更多(因为通过旋转重新访问了某个字符位置),那么您也可以返回“NO”。

对于递归部分,您可以先查找str1 中出现次数最少的字符,这样就不必多次重试。您还可以跟踪str1 中匹配字符的距离:如果它们相距太远(大于子字符串的总大小),则继续朝那个方向前进是没有用的。

所有这些都在下面实现:

function task18(str, rotations) 
    // convert second argument: extract single rotations and convert to signed offsets
    rotations = rotations.replace(/R\s*/g, "-").match(/-?\d/g).map(Number);
    
    // Make a naive check to exclude rotation strings that are too long
    if (rotations.length > str.length) return "NO"; // too many characters will be selected

    // Register at which indexes a character occurs (as there may be duplicate characters)
    let occurrences = Object.fromEntries(Array.from(str, c => [c, []]));
    Array.from(str, (c, i) => occurrences[c].push(i)); 
    // Count characters in str so to be able to detect a "NO" sooner.
    let available = Object.fromEntries(Array.from(str, c => [c, occurrences[c].length]));

    // Don't actually rotate the string, but maintain a current index
    let current = 0;
    let result = []; // The selected characters
    for (let rot of rotations) 
        let c = str[current = (current + str.length + rot) % str.length];
        if (!available[c]--) return "NO"; // too many of the same character
        result.push(c);
    

    // Reorder characters, so those which have the least available occurrences
    //  in the input string come first.
    // This will optimise the depth first search for an anagram.
    result.sort((a, b) => available[a] - available[b]);

    // Perform a depth-first search for an anagram match
    return (function dfs(i=0, first=str.length, last=-1) 
        // first/last are the extreme indexes in str that have been matched
        if (last - first >= result.length) return false; // subsequence will have gaps; backtrack
        if (i >= result.length) return true; // all characters are allocated in a subsequence
        let c = result[i];
        let occ = occurrences[c];
        let usedoccurrences = occ.length - available[c];
        for (let j = 0; j <= available[c]; j++) 
            if (dfs(i+1, Math.min(first, occ[j]), Math.max(last, occ[j+usedoccurrences-1]))) 
                return true;
            
        
        return false; // backtrack
    )() ? "YES" : "NO"; // immediately invoke dfs: returns a boolean


// Test cases
console.log(task18("abcde","L 3 R 2 R 4")); // YES
console.log(task18("linkinpark", "L 6 R 5 L 4")); // YES
console.log(task18("carrace", "L 2 R 2 L 3")); // NO
console.log(task18("pnesumonoultramicroscopicsilicovolcanoconiosisfloccinaucinihilipilification", "R9R1L4L9")); // YES

【讨论】:

感谢所有案例都通过了....我不知道我需要多长时间才能编写出如此高效的代码。再次感谢您的宝贵时间【参考方案2】:

这是一个不修改中间字符串的解决方案,而只是在每次旋转后跟踪第一个字母的位置。

// After applying first rotation L 3, the string is: 'deabc'. Here, the first character is 'd'
// After applying second rotation R 2, the string is: 'bcdea'. Here, the first character is 'b'
// After applying third rotation R 4, the string is: 'cdeab'. Here, the first character is 'c'
// Thus, after all the rotations the FIRSTCHARSTRING string will be "dbc" which is an anagram of a sub string of original string "abcde".

// Check if the result is an anagram of a substring of the full string.
const isAnagram = (full, part) =>    
  let isPartAnagram = true;
  partAsArray = part.split("");
  for (let i in partAsArray) 
    let c = partAsArray[i];
    let pos = full.indexOf(c);
    // If the letter is not part anymore of the string, it's not an anagram.
    if (pos === -1) 
      isPartAnagram = false;
      return;
    
    // Remove char from string.
    full = full.substring(0, pos) + full.substring(pos+1)
  
  return isPartAnagram;


const task18 = (str1, str2) => 
  // Let's remove whitespace. We don't need that.
  str2 = str2.replace(/\s/g, "");
  
  let result = "";
  let currPos = 0;
  // mod is used to ensure that array boundaries are no problem
  let mod = str1.length;
  for (let i = 0; i < str2.length; i++) 
    if (str2[i] === "L") 
      currPos = (currPos + str2[++i]) % mod;
      // Add 'pseudofirst' letter to result.
      result += str1[currPos];
     else 
      currPos = (mod + currPos - str2[++i]) % mod;
      // Add 'pseudofirst' letter to result.
      result += str1[currPos];
    
  
  
  let answer = isAnagram(str1, result) ? 'YES' : 'NO'
  console.log(str1, str2, result, answer);
  
  return answer;


task18("abcde","L 3 R 2 R 4");
task18("linkinpark", "L 6 R 5 L 4");
task18("carrace", "L 2 R 2 L 3") // should return NO
task18("pnesumonoultramicroscopicsilicovolcanoconiosisfloccinaucinihilipilification", "R9R1L4L9") // should return yes

【讨论】:

结果应该是 YES 但给出 NO 作为答案 这也是一个测试用例 ans YES - ("linkinpark", "L 6 R 5 L 4") 感谢您的努力。它几乎可以正常工作,但对于这些测试用例(“carrace”、“L 2 R 2 L 3”)应返回 NO,pnesumonoultramicroscopicsilicovolcanoconiosisfloccinaucinihilipilification R9R1L4L9 应返回 yes 修复了最后一个测试用例。你能解释一下为什么 ("carrace", "L 2 R 2 L 3") 应该返回 NO 吗? 因为它不是字谜。对于大多数以 NO 为答案的测试用例,您的解决方案都失败了

以上是关于JS 程序将给定的字符串沿指定方向旋转指定幅度的主要内容,如果未能解决你的问题,请参考以下文章

js 截取给定字符后面的字符

根据相机方向移动

Python图形库Turtle

N字形变化 flag标签转换方向

(Swift SpriteKit) 沿触摸方向旋转精灵

使css3过渡始终沿同一方向旋转