常用数据结构-数组&字符串

数据结构是算法的基石,如果没有扎实的数据结构基础,要想把算法学好甚至融会贯通是非常困难的,而优秀的算法又往往取决于你采用哪种数据结构

数组、字符串(Array & String)
字符串转化

数组和字符串是最基本的数据结构,在很多编程语言中都有着非常相似的性质,围绕着这两者的算法面试题是最多的

很多时候,在分析字符串相关面试题的过程中,我们往往要针对字符串中的每一个字符进行分析和处理,甚至有时候我们得先把给定的字符串转换成字符数组后再进行分析和处理

举例:翻转字符串 "algorithm"

CgoB5l2IRiCATj5LAGJa69BtQRA357.gif

注意:字符串中的字符是不允许被修改的,我们只能将原字符串转换成字符数组针对每一个字符进行分析和处理
解法:

<?php
/**
 * 在这里我们不使用 php built in function 处理,在 php 中有一个built in function strRev 一行代码即可实现翻转字符串,
 * 但是在面试的时候这肯定是面试官不愿意看到结果,面试在一定程度上考察的是我们处理问题的思维逻辑。如果要是在实际开发中我们可以使用 php built in function
 *
 * 另外需要注意的是,要想实现字符串翻转我们在这里需要将给定的字符串转换成字符数组,然后再分析处理。在 php 中的字符串可以直接作为数组处理,比如代码:
 * echo $str[4]; 输出结果为 r,则代表的是该字符串的第四个字符为 r
 */

// 待测试字符串
$str = 'algorithm';
function str_rev($str) {
    // 结合 for 循环,将第二个条件置为 true,模拟死循环,计算字符串的长度
    for($i = 0;true;$i++) {
        if(!isset($str[$i])) {
            break;
        }
    }

    // 通过上面 for 循环计算出字符串长度,下面我们根据使用下标获取字符数组元素,将字符串从末尾开始循环进行字符串拼接
    $newStr = '';
    for($j = $i - 1;$j >= 0;$j--) {
        $newStr .= $str[$j];
    }
    return $newStr;
}

// 输出
var_dump(str_rev($str));
数组的优缺点

掌握一种数据结构,就必须要了解这种数据结构的优缺点,这样我们才能根据其特性选择适合我们算法的数据结构,数组的优点:

  • 数组支持随机访问,可根据数组下标在时间复杂度为 O(1) 的情况下访问数组元素

而数组的缺点在于:

  • 数组在分配内存空间前需要预估下要存储数据元素的大小,如果分配内存空间不够需要手动扩容,这在一定程度上会耗费资源,使得性能受到一定影响
  • 数组的插入和删除操作,均需要移动元素,这使得其插入和删除操作的时间复杂度为 O(n)

所以我们在是否选择数组作为我们算法的数据结构时,需要考虑到数组的优缺点,比如算法中查询、插入和删除哪种操作比较多,根据数据确定知道数组明显不擅长元素插入和删除

例题分析

给定两个字符串 st,编写一个函数来判断 t 是否是 s 的字母异位词
示例 1:

输入:s = "anagram",t = "nagaram"
输出:true

示例 2:

输入:s = "rat",t = "car"
输出:false

说明:你可以假设字符串只包含小写字母

字母异位词,也就是两个字符串中相同字符的数量要对应相等。例如,s 等于 "anagram",t 等于 "nagaram", s 和 t 就互为字母异位词。因为他们都包含三个字符 a,一个字符 g,一个字符 m,一个字符 n ,以及一个字符 r。而当 s 为 "rat" ,t 为 "cat" 的时候,s 和 t 不互为字母异位词

具体代码实现如下:

class Solution {

    /**
     * @param String $s
     * @param String $t
     * @return Boolean
     */
    function isAnagram($s, $t) {
        // 首先互为字母异位词的两个字符串长度一定相等
        // 使用 for 循环分别计算两个字符串的长度
        // 计算字符串 s 的长度
        for($i = 0;true;$i ++) {
            if(!isset($s[$i])) {
                break;
            }
        }

        // 计算字符串 t 的长度
        for($j = 0;true;$j ++) {
            if(!isset($t[$j])) {
                break;
            }
        }

        // 判断两个字符串长度是否相等,如果不相等,这两个字符串一定不互为字母异位词
        if($i != $j) {
            return false;
        }

        // 判断当两个字符串同时输入的都是空字符串时,则两个字符串也互为字母异位词
        if($i == 0 && $j == 0) {
            return true;
        }

        // 定义一个字符数组,使用 26 个小写字母作为数组的 key,将 每个 key 对应的 value 统一置为 0
        $letterArr = array('a'=>0,'b'=>0,'c'=>0,'d'=>0,'e'=>0,'f'=>0,'g'=>0,'h'=>0,'i'=>0,'j'=>0,'k'=>0,'l'=>0,'m'=>0,'n'=>0,'o'=>0,'p'=>0,'q'=>0,'r'=>0,'s'=>0,'t'=>0,'u'=>0,'v'=>0,'w'=>0,'x'=>0,'y'=>0,'z'=>0);
        // 计算字符串 s 中的字符 在字符数组 letterArr 中出现的个数
        for($m = 0;$m < $i;$m++){
            if(isset($letterArr[$s[$m]])) {
                $letterArr[$s[$m]]++;
            }else{
                $letterArr[$s[$m]] = 1;
            }
        }

        // 计算字符串 t 中的字符 在字符数组中 letterArr 出现的个数,并将其减 1
        for($n = 0;$n < $j;$n++) {
            if(!isset($letterArr[$t[$n]]) || $letterArr[$t[$n]] == 0) {
                return false;
            }
            if(isset($letterArr[$t[$n]])) {
                $letterArr[$t[$n]]--;
            }
        }
        return true;
    }
}

$solution = new Solution();
$s = 'aacc';
$t = 'ccac';
$solution = $solution->isAnagram($s,$t);
echo $solution;

上面代码是我在 leetcode 提交的具体实现逻辑,在上述代码中我未使用 php 内置函数,在计算字符串长度时,使用 for 循环模拟死循环,解题思路:
一个重要前提是假设输入的两个字符串中的字符都是小写字母,小写字母我们知道一共有 26 个,因此:

  • 创建一个包含 26 个小写字母的字符数组,并将每个小写字母作为数组的 key,每个 key 对应的 value 初始化为 0,将出现在字符串 s 中的字符加 1,而将出现在字符串 t 中的字符减 1,最后判断每个小写字母对应的值 value 是否都为 0,如果都为 0,则说明输入的两个字符串互为字母异位词
例题分析

翻转字符串:编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。
不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。
你可以假设数组中的所有字符都是 ASCII 码表中的可打印字符。
示例 1:

输入:["h","e","l","l","o"]
输出:["o","l","l","e","h"]

示例 2:

输入:["H","a","n","n","a","h"]
输出:["h","a","n","n","a","H"]

具体代码实现如下:

class Solution {

    /**
     * @param String[] $s
     * @return NULL
     */
    function reverseString(&$s) {
        for($i = 0;true;$i++) {
          if(!isset($s[$i])) {
            break;
          }
        }


        for($n = 0;$n < $i;$n++) {
           $temp = $s[$n];
           $s[$n] = $s[$i - 1];
           $s[$i - 1] = $temp;
           $i--;
        }

        return $s;
    }
}

$str = ["h","e","l","l","o"];
$solution  = new Solution();
$result = $solution->reverseString($str);
var_dump($result);

解题思路
使用两个指针,一个指针指向字符数组的第一个字符,一个指向字符数组的最后一个字符,然后相互交换。交换之后,两个指针向中央一步步地靠拢,直到两个指针相遇。这是一种比较快速和直观的方法

例题分析

替换空格:请实现一个函数,把字符串 s 中的空格替换成 "%20"
示例 1:

输入:s = "We are happy."
输出:"We%20are%20happy."

这道题目是剑指offer上面的一道原题,在力扣上这道题目的难度等级是简单,我们来分析下这道题目,如果面试中拿到面试官给我们的题目,我们首先不要着急答题,先和面试官沟通清楚题目的要求,有的面试官可能不会说,让我们自己主动思考,比如上面这道题目。

看到上面这道题目我们应该想到有两种情况存在,一个是在原有字符串的基础上直接替换;一个是创建新字符串,在新字符串上替换。如果是在原始字符串上替换的话,那么需要保证字符串后面有足够多的空闲内存,因为字符串中的空格被替换后字符串的长度变长了,之前处于空格后面的字符需要向后移动,如果字符串后面没有足够多的内存空间,那么有可能会出现内存覆盖的问题,这些需要向面试官确认,我们来看下这两情况分别对应的具体实现:
创建新字符串,在新字符串上替换

class Solution {

    /**
     * @param String $s
     * @return String
     */
    function replaceSpace($s) {
        // 计算字符串的长度
        for ($sLength = 0;true;$sLength++) {
            if(!isset($s[$sLength])) {
                break;
            }
        }

        $S = "";
        for ($i = 0;$i < $sLength;$i++) {
            if($s[$i] == " ") {
                $S .= '%20';
            }else{
                $S .= $s[$i];
            }
        }

        return $S;
    }
}

$str = 'We are happy.';
$solution = new Solution();
$result = $solution->replaceSpace($str);
var_dump($result);
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350