Algorithm brushing questions - string - replace spaces

Title: Sword Pointing to Offer 05. Replace spaces

link

Please implement a function to replace each space in the string s with "%20".

Example 1:
Input: s = "We are happy."
Output: "We%20are%20happy."

train of thought

If you want to take this subject to the extreme, don't just use extra auxiliary space!

First expand the array to the size after replacing each space with "%20".

Then replace the space from the back to the front, that is, the double pointer method, the process is as follows:

i points to the end of the new length and j points to the end of the old length.

[External link picture transfer failed, the source site may have an anti-theft link mechanism, it is recommended to save the picture and upload it directly (img-UOQ3D3Dc-1687011835976)(https://code-thinking.cdn.bcebos.com/gifs/%E6% 9B%BF%E6%8D%A2%E7%A9%BA%E6%A0%BC.gif)]

Some students asked, why do we need to fill from the back to the front, can't we fill from the front to the back?

Filling from front to back is an O(n^2) algorithm, because every time an element is added, all elements after the added element must be moved backwards.

In fact, for many array filling problems, you can expand the array in advance with the filled size, and then operate from the back to the front.

This has two advantages:

  1. No need to apply for a new array.
  2. Filling elements from the back to the front avoids the problem of moving all the elements behind the added element to the back every time an element is added when filling the elements from the front to the back.

Users whose time complexity and space complexity both exceed 100%.

The C++ code is as follows:

class Solution {
public:
    string replaceSpace(string s) {
        int count = 0; // 统计空格的个数
        int sOldSize = s.size();
        for (int i = 0; i < s.size(); i++) {
            if (s[i] == ' ') {
                count++;
            }
        }
        // 扩充字符串s的大小,也就是每个空格替换成"%20"之后的大小
        s.resize(s.size() + count * 2);
        int sNewSize = s.size();
        // 从后先前将空格替换为"%20"
        for (int i = sNewSize - 1, j = sOldSize - 1; j < i; i--, j--) {
            if (s[j] != ' ') {
                s[i] = s[j];
            } else {
                s[i] = '0';
                s[i - 1] = '2';
                s[i - 2] = '%';
                i -= 2;
            }
        }
        return s;
    }
};
  • Time complexity: O(n)
  • Space complexity: O(1)

Counting this question at this time, we have already done seven questions related to double pointers:

expand

Here is also to expand the difference between strings and arrays.

A string is a finite sequence of characters, which can also be understood as a character array, but many languages ​​have special rules for strings. Next, let me talk about strings in C/C++.

In C language, when a string is stored in an array, the end character '\0' is also stored in the array, and this is used as a sign of whether the string ends.

For example this code:

char a[5] = "asd";
for (int i = 0; a[i] != '\0'; i++) {
}

In C++, a string class is provided, and the string class will provide a size interface, which can be used to judge whether the string class string is over, so there is no need to use '\0' to judge whether it is over.

For example this code:

string a = "asd";
for (int i = 0; i < a.size(); i++) {
}

So what is the difference between vector< char > and string?

In fact, there is no difference in basic operations, but string provides more interfaces related to string processing. For example, string overloads +, but vector does not.

So if we want to deal with strings, we will still define a string type.

other language versions

C:

char* replaceSpace(char* s){
    //统计空格数量
    int count = 0;
    int len = strlen(s);
    for (int i = 0; i < len; i++) {
        if (s[i] == ' ') {
            count++;
        }
    }

    //为新数组分配空间
    int newLen = len + count * 2;
    char* result = malloc(sizeof(char) * newLen + 1);
    //填充新数组并替换空格
    for (int i = len - 1, j = newLen - 1; i >= 0; i--, j--) {
        if (s[i] != ' ') {
            result[j] = s[i];
        } else {
            result[j--] = '0';
            result[j--] = '2';
            result[j] = '%';
        }
    }
    result[newLen] = '\0';

    return result;
}

Java:

//使用一个新的对象,复制 str,复制的过程对其判断,是空格则替换,否则直接复制,类似于数组复制
public static String replaceSpace(String s) {
        if (s == null) {
            return null;
        }
        //选用 StringBuilder 单线程使用,比较快,选不选都行
        StringBuilder sb = new StringBuilder();
        //使用 sb 逐个复制 s ,碰到空格则替换,否则直接复制
        for (int i = 0; i < s.length(); i++) {
            //s.charAt(i) 为 char 类型,为了比较需要将其转为和 " " 相同的字符串类型
            //if (" ".equals(String.valueOf(s.charAt(i)))){}
            if (s.charAt(i) == ' ') {
                sb.append("%20");
            } else {
                sb.append(s.charAt(i));
            }
        }
        return sb.toString();
    }

//方式二:双指针法
public String replaceSpace(String s) {
    if(s == null || s.length() == 0){
        return s;
    }
    //扩充空间,空格数量2倍
    StringBuilder str = new StringBuilder();
    for (int i = 0; i < s.length(); i++) {
        if(s.charAt(i) == ' '){
            str.append("  ");
        }
    }
    //若是没有空格直接返回
    if(str.length() == 0){
        return s;
    }
    //有空格情况 定义两个指针
    int left = s.length() - 1;//左指针:指向原始字符串最后一个位置
    s += str.toString();
    int right = s.length()-1;//右指针:指向扩展字符串的最后一个位置
    char[] chars = s.toCharArray();
    while(left>=0){
        if(chars[left] == ' '){
            chars[right--] = '0';
            chars[right--] = '2';
            chars[right] = '%';
        }else{
            chars[right] = chars[left];
        }
        left--;
        right--;
    }
    return new String(chars);
}

Go:

// 遍历添加
func replaceSpace(s string) string {
    
    
    b := []byte(s)
    result := make([]byte, 0)
    for i := 0; i < len(b); i++ {
    
    
        if b[i] == ' ' {
    
    
            result = append(result, []byte("%20")...)
        } else {
    
    
            result = append(result, b[i])
        }
    }
    return string(result)
}

// 原地修改
func replaceSpace(s string) string {
    
    
    b := []byte(s)
    length := len(b)
    spaceCount := 0
    // 计算空格数量
    for _, v := range b {
    
    
        if v == ' ' {
    
    
            spaceCount++
        }
    }
    // 扩展原有切片
    resizeCount := spaceCount * 2
    tmp := make([]byte, resizeCount)
    b = append(b, tmp...)
    i := length - 1
    j := len(b) - 1
    for i >= 0 {
    
    
        if b[i] != ' ' {
    
    
            b[j] = b[i]
            i--
            j--
        } else {
    
    
            b[j] = '0'
            b[j-1] = '2'
            b[j-2] = '%'
            i--
            j = j - 3
        }
    }
    return string(b)
}

python:

class Solution:
    def replaceSpace(self, s: str) -> str:
        counter = s.count(' ')
        
        res = list(s)
        # 每碰到一个空格就多拓展两个格子,1 + 2 = 3个位置存’%20‘
        res.extend([' '] * counter * 2)
        
        # 原始字符串的末尾,拓展后的末尾
        left, right = len(s) - 1, len(res) - 1
        
        while left >= 0:
            if res[left] != ' ':
                res[right] = res[left]
                right -= 1
            else:
                # [right - 2, right), 左闭右开
                res[right - 2: right + 1] = '%20'
                right -= 3
            left -= 1
        return ''.join(res)
            
class Solution:
    def replaceSpace(self, s: str) -> str:
        # method 1 - Very rude
        return "%20".join(s.split(" "))

        # method 2 - Reverse the s when counting in for loop, then update from the end.
        n = len(s)
        for e, i in enumerate(s[::-1]):
            print(i, e)
            if i == " ":
                s = s[: n - (e + 1)] + "%20" + s[n - e:]
            print("")
        return s

javaScript:

/**
 * @param {string} s
 * @return {string}
 */
 var replaceSpace = function(s) {
    
    
   // 字符串转为数组
  const strArr = Array.from(s);
  let count = 0;

  // 计算空格数量
  for(let i = 0; i < strArr.length; i++) {
    
    
    if (strArr[i] === ' ') {
    
    
      count++;
    }
  }

  let left = strArr.length - 1;
  let right = strArr.length + count * 2 - 1;

  while(left >= 0) {
    
    
    if (strArr[left] === ' ') {
    
    
      strArr[right--] = '0';
      strArr[right--] = '2';
      strArr[right--] = '%';
      left--;
    } else {
    
    
      strArr[right--] = strArr[left--];
    }
  }

  // 数组转字符串
  return strArr.join('');
};

TypeScript:

function replaceSpace(s: string): string {
    
    
    let arr: string[] = s.split('');
    let spaceNum: number = 0;
    let oldLength: number = arr.length;
    for (let i = 0; i < oldLength; i++) {
    
    
        if (arr[i] === ' ') {
    
    
            spaceNum++;
        }
    }
    arr.length = oldLength + 2 * spaceNum;
    let cur: number = oldLength - 1;
    for (let i = arr.length - 1; i >= 0; i--, cur--) {
    
    
        if (arr[cur] !== ' ') {
    
    
            arr[i] = arr[cur]
        } else {
    
    
            arr[i] = '0';
            arr[--i] = '2';
            arr[--i] = '%';
        }
    }
    return arr.join('');
};

Swift:

func replaceSpace(_ s: String) -> String {
    
    
    var strArr = Array(s)
    var count = 0

    // 统计空格的个数
    for i in strArr {
    
    
        if i == " " {
    
    
            count += 1
        }
    }
    // left 指向旧数组的最后一个元素
    var left = strArr.count - 1
    // right 指向扩容后数组的最后一个元素(这里还没对数组进行实际上的扩容)
    var right = strArr.count + count * 2 - 1

    // 实际对数组扩容
    for _ in 0..<(count * 2) {
    
    
        strArr.append(" ")
    }

    while left < right {
    
    
        if strArr[left] == " " {
    
    
            strArr[right] = "0"
            strArr[right - 1] = "2"
            strArr[right - 2] = "%"
            left -= 1
            right -= 3
        } else {
    
    
            strArr[right] = strArr[left]
            left -= 1
            right -= 1
        }
    }

    return String(strArr)
}

Scala:

Method 1: Double pointer

object Solution {
    
    
  def replaceSpace(s: String): String = {
    
    
    var count = 0
    s.foreach(c => if (c == ' ') count += 1) // 统计空格的数量
    val sOldSize = s.length // 旧数组字符串长度
    val sNewSize = s.length + count * 2 // 新数组字符串长度
    val res = new Array[Char](sNewSize) // 新数组
    var index = sNewSize - 1 // 新数组索引
    // 逆序遍历
    for (i <- (0 until sOldSize).reverse) {
    
    
      if (s(i) == ' ') {
    
    
        res(index) = '0'
        index -= 1
        res(index) = '2'
        index -= 1
        res(index) = '%'
      } else {
    
    
        res(index) = s(i)
      }
      index -= 1
    }
    res.mkString
  }
}

Method 2: Use a collection, add %20 when encountering a space

object Solution {
    
    
  import scala.collection.mutable.ListBuffer
  def replaceSpace(s: String): String = {
    
    
    val res: ListBuffer[Char] = ListBuffer[Char]()
    for (i <- s.indices) {
    
    
      if (s(i) == ' ') {
    
    
        res += '%'
        res += '2'
        res += '0'
      }else{
    
    
        res += s(i)
      }
    }
    res.mkString
  }
}

Method 3: use map

object Solution {
    
    
  def replaceSpace(s: String): String = {
    
    
    s.map(c => if(c == ' ') "%20" else c).mkString
  }
  }

PHP:

function replaceSpace($s){
    
    
    $sLen = strlen($s);
    $moreLen = $this->spaceLen($s) * 2;

    $head = $sLen - 1;
    $tail = $sLen + $moreLen - 1;

    $s = $s . str_repeat(' ', $moreLen);
    while ($head != $tail) {
    
    
        if ($s[$head] == ' ') {
    
    
            $s[$tail--] = '0';
            $s[$tail--] = '2';
            $s[$tail] = '%';
        } else {
    
    
            $s[$tail] = $s[$head];
        }
        $head--;
        $tail--;
    }
    return $s;
}
// 统计空格个数
function spaceLen($s){
    
    
    $count = 0;
    for ($i = 0; $i < strlen($s); $i++) {
    
    
        if ($s[$i] == ' ') {
    
    
            $count++;
        }
    }
    return $count;
}

Rust

impl Solution {
    pub fn replace_space(s: String) -> String {
        let mut len: usize = s.len();
        let mut s = s.chars().collect::<Vec<char>>();
        let mut count = 0;
        for i in &s {
            if i.is_ascii_whitespace() {
                count += 1;
            }
        }
        let mut new_len = len + count * 2;
        s.resize(new_len, ' ');
        while len < new_len {
            len -= 1;
            new_len -= 1;
            if s[len].is_ascii_whitespace() {
                s[new_len] = '0';
                s[new_len - 1] = '2';
                s[new_len - 2] = '%';
                new_len -= 2;
            }
            else { s[new_len] = s[len] }
        }
        s.iter().collect::<String>()
    }
}

Guess you like

Origin blog.csdn.net/weixin_42439274/article/details/131265471