Rust: codewars的Simple Substitution Cipher Helper算法题、N种不简单的解法集

codewars是一个不错的刷题的网站,特别是对于rust爱好者而者,资源稀缺,是打发时光的利器。

今天不是专门安利codewars而来,主要是谈一道简单的加密和解密算法题。
说明:来源于codewars,Simple Substitution Cipher Helper。

一、要求如下:

其实就是26个字母,打乱后,但一一对应。要求对任一字符串,能进行加密和解密。

比如

let map1 = "abcdefghijklmnopqrstuvwxyz";
let map2 = "etaoinshrdlucmfwypvbgkjqxz";

let cipher = Cipher::new(map1, map2);
cipher.encode("abc") // => "eta"
cipher.encode("xyz") // => "qxz"
cipher.encode("aeiou") // => "eirfg"

cipher.decode("eta") // => "abc"
cipher.decode("qxz") // => "xyz"
cipher.decode("eirfg") // => "aeiou"

如果超出26个字母以外的字符,不加密。即”好”=》“好”

二、N种不同的算法,大开眼界

只能说,牛人太多,爽爽爽!这个是最好的教材。除本法提交的算法外,在此选集了近10种codewars中的精彩的解法,供平时学习。

1、个人提交的算法

use std::collections::HashMap;
struct Cipher {
    encode: HashMap<String, String>,
    decode: HashMap<String, String>,
}

impl Cipher {
    fn new(map1: &str, map2: &str) -> Cipher {
        let _encode = map1.chars()
            .map(|x| x.to_string())
            .zip(map2.chars().map(|y| y.to_string()))
            .collect::<HashMap<String, String>>();
        let _decode = map2.chars()
            .map(|x| x.to_string())
            .zip(map1.chars().map(|y| y.to_string()))
            .collect::<HashMap<String, String>>();
        Cipher {
            encode: _encode,
            decode: _decode,
        }
    }

    fn encode(&self, string: &str) -> String {
        let mut _strs = String::from("");
        let strs: Vec<_> = string.chars()
            .map(|x| match self.encode.get(&x.to_string()) {
                Some(s) => _strs.push_str(s),
                _ => _strs.push_str(&x.to_string()),
            })
            .collect();
        _strs
    }

    fn decode(&self, string: &str) -> String {
        let mut _strs = String::from("");
        let strs: Vec<_> = string.chars()
            .map(|x| match self.decode.get(&x.to_string()) {
                Some(s) => _strs.push_str(s),
                _ => _strs.push_str(&x.to_string()),
            })
            .collect();
        _strs
    }
}

2、codewars的最佳算法

struct Cipher {
  map: Vec<(char, char)>
}

impl Cipher {
  fn new(map1: &str, map2: &str) -> Cipher {
    Cipher {
      map: map1.chars().zip(map2.chars()).collect()
    }
  }

  fn encode(&self, string: &str) -> String {
    string.chars().map(|c| self.map.iter().find(|x| x.0 == c).map_or(c, |y| y.1)).collect()
  }

  fn decode(&self, string: &str) -> String {
    string.chars().map(|c| self.map.iter().find(|x| x.1 == c).map_or(c, |y| y.0)).collect()
  }
}

3、其它算法

use std::collections::HashMap;

struct Cipher {
  encode_map: HashMap<char, char>,
  decode_map: HashMap<char, char>,
}

impl Cipher {
  fn new(map1: &str, map2: &str) -> Cipher {
    let mut encode_map = HashMap::new();
    encode_map.extend(map1.chars().zip(map2.chars()));

    let mut decode_map = HashMap::new();
    decode_map.extend(map2.chars().zip(map1.chars()));

    Cipher { encode_map: encode_map, decode_map: decode_map }
  }

  fn encode(&self, string: &str) -> String {
    string.chars().map(|c| self.encode_map.get(&c).map_or(c, |v| *v)).collect()
  }

  fn decode(&self, string: &str) -> String {
    string.chars().map(|c| self.decode_map.get(&c).map_or(c, |v| *v)).collect()
  }
}

4、BTreeMap

use std::collections::BTreeMap;

struct Cipher {
  // We need a bidirectional cipher implementation, with dictionary per direction.
  // BTreeMap should likely work faster than HashMap with simplest hasher in our case.
  etree: BTreeMap<char, char>,
  dtree: BTreeMap<char, char>,
}

impl Cipher {
  fn new(map1: &str, map2: &str) -> Cipher {
    Cipher {
      // Hopefully BTreeMap is created balanced.
      etree: map1.chars().zip(map2.chars()).collect(),
      dtree: map2.chars().zip(map1.chars()).collect(),
    }
  }

  // Here be dragons, krakens, sandworms and impaired (de-)referencing conventions.

  fn encode(&self, string: &str) -> String {
    string.chars().map(|c| self.etree.get(&c).cloned().unwrap_or(c)).collect()
  }

  fn decode(&self, string: &str) -> String {
    string.chars().map(|c| self.dtree.get(&c).cloned().unwrap_or(c)).collect()
  }
}

5、String

struct Cipher {
  map1: String,
  map2: String,
}

impl Cipher {
  fn new(map1: &str, map2: &str) -> Cipher {
    Cipher { map1: map1.into(), map2: map2.into()}
  }

  fn encode(&self, string: &str) -> String {
    string.chars().map(
    |c| {
      match self.map1.find(c) {
        Some(i) => self.map2.chars().nth(i).unwrap(),
        _ => c
      }
    }
    ).collect()
  }

  fn decode(&self, string: &str) -> String {
    string.chars().map(
    |c| {
      match self.map2.find(c) {
        Some(i) => self.map1.chars().nth(i).unwrap(),
        _ => c
      }
    }
    ).collect()
  }
}

6、Vec

struct Cipher {
  from: Vec<u8>,
  to: Vec<u8>,
}

impl Cipher {
  fn new(map1: &str, map2: &str) -> Cipher {
    Cipher {
      from: map1.as_bytes().to_vec(),
      to: map2.as_bytes().to_vec(),
    }
  }

  fn encode(&self, string: &str) -> String {
    string.chars()
      .map(|c| self.from.iter().position(|&f| f == c as u8).map_or(c, |p| self.to[p] as char))
      .collect()
  }

  fn decode(&self, string: &str) -> String {
    string.chars()
      .map(|c| self.to.iter().position(|&f| f == c as u8).map_or(c, |p| self.from[p] as char))
      .collect()
  }
}

7、

use std::collections::HashMap;

fn get_default(m: &HashMap<char,char>,k: &char) -> char {
    match m.get(k) {
        Some(val) => *val,
        None => *k
    }
}

struct Cipher {
  encoding: HashMap<char,char>,
  decoding: HashMap<char,char>
}

impl Cipher {
  fn new(map1: &str, map2: &str) -> Cipher {
        let mut encoding = HashMap::new();
        let mut decoding = HashMap::new();
        for (x,y) in map1.chars().zip(map2.chars()) {
            encoding.insert(x,y);
            decoding.insert(y,x);
        }
        Cipher{encoding:encoding,decoding:decoding}
  }

  fn encode(&self, string: &str) -> String {
    string.chars().map(|c| get_default(&self.encoding,&c).to_string())
      .collect::<Vec<String>>().join("")
  }

  fn decode(&self, string: &str) -> String {
    string.chars().map(|c| get_default(&self.decoding,&c).to_string())
      .collect::<Vec<String>>().join("")
  }
}

8、

use std::collections::HashMap;

struct Cipher {
  encode: HashMap<char, char>,
  decode: HashMap<char, char>,
}

fn _code(map: &HashMap<char, char>, string: &str) -> String {
    string.chars()
      .map(|x| map.get(&x).unwrap_or(&x).clone())
      .collect()
}

impl Cipher {
  fn new(map1: &str, map2: &str) -> Cipher {
    Cipher {
      encode: map1.chars()
                .zip(map2.chars())
                .collect(),
      decode: map2.chars()
                .zip(map1.chars())
                .collect(),
    }
  }

  fn encode(&self, string: &str) -> String {
    _code(&self.encode, string)
  }

  fn decode(&self, string: &str) -> String {
    _code(&self.decode, string)
  }
}

9、

struct Cipher<'a> {
    map1:&'a [u8],
    map2:&'a [u8]
}

impl<'a> Cipher<'a> {
    fn new(map1: &'a str, map2: &'a str) -> Cipher<'a> {
        Cipher{map1:map1.as_bytes(), map2:map2.as_bytes()}
    }

    fn encode(&self, string: &str) -> String {
        string.bytes()
            .map(|b| 
                self.map1
                    .iter()
                    .position(|&m| b==m)
                    .and_then(|i| self.map2.get(i))
                    .cloned()
                    .unwrap_or(b) as char
            )
            .collect()
    }

    fn decode(&self, string: &str) -> String {
        self.decoder().encode(string)
    }

    fn decoder(&self) -> Cipher{
        Cipher{map1:self.map2, map2:self.map1}
    }
}

10、

struct Cipher {
  table : std::collections::HashMap<char,char>
}

impl Cipher {
  fn new(map1: &str, map2: &str) -> Cipher {
    Cipher {
      table : map1.chars().zip(map2.chars()).collect()
    }
  }

  fn encode(&self, string: &str) -> String {
    string.chars().map(|x| self.table.get(&x).cloned().unwrap_or(x)).collect()
  }

  fn decode(&self, string: &str) -> String {
    string.chars().map(|x| self.decode_char(x)).collect()
  }
  fn decode_char(&self, c: char) -> char {
    self.table.iter().find(|kv| *kv.1 == c).map(|kv| *kv.0).unwrap_or(c)
  }
}

11、个人认为的最佳解法

use std::collections::HashMap;

struct Cipher {
  encode: HashMap<char, char>,
  decode: HashMap<char, char>
}

impl Cipher {
  fn new(map1: &str, map2: &str) -> Self {
    let encode = map1.chars().zip(map2.chars()).collect();
    let decode = map2.chars().zip(map1.chars()).collect();
    Cipher{encode: encode, decode: decode}
  }

  fn encode(&self, string: &str) -> String {
    string.chars().map(|ref c| *self.encode.get(c).unwrap_or(c)).collect()
  }

  fn decode(&self, string: &str) -> String {
    string.chars().map(|ref c| *self.decode.get(c).unwrap_or(c)).collect()
  }
}

三、个别点评

看了其它人10种解法外,个人认为第11种解法最佳,思路清晰,代码简单,最为优雅,第10种也差不多,当然,各种优势。

我的解法的思路虽然相同,但用String并不是一个好的选择,过于笨重,增加了不少的代码量。

1、用char代替String

//在上面场景中,HashMap<char, char>较HashMap<String, String>结构更轻巧。
fn new(map1: &str, map2: &str) {
    let _encode = map1.chars()
        .zip(map2.chars())
        .collect::<HashMap<char, char>>();
}
//没有过多的转化

2、使用unwrap_or,可以省了一大段的代码:

    string.chars().map(|ref c| *self.encode.get(c).unwrap_or(c)).collect()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值