现代 Java 应用程序有大量的字符串操作,例如,Web 服务 API 调用(JSON、REST、SOAP 等)、外部数据源调用(SQL、从 DB 返回的数据等)以及文本解析和文本创建等。因此,字符串对象很容易就占据了约至少 30% 的内存。然而,这些 String 对象中的大多数都是重复的,这些字符串的重复浪费了大量内存。因此,优化重复字符串对象浪费的内存是 Java 非常受欢迎的功能之一。在 G1 中,Java 就对此功能做了支持。
在本文中,将分享一些常见的编程面试问题,这些问题来自于不同经验水平的程序员,囊括从刚大学毕业的人到具有一到两年经验的程序员。
经常有读者留言,请我讲讲那些比较经典的算法,我觉得有这个必要,主要有以下原因: 1、经典算法之所以经典,一定是因为有独特新颖的设计思想,那当然要带大家学习一波。 2、我会尽量从最简单、最基本的算法切入,带你亲手推导出来这些经典算法的设计思想,自然流畅地写出最终解法。一方面消除大多数人对算法的恐惧,另一方面可以避免很多人对算法死记硬背的错误习惯。 我之前用状态机的思路讲解了 KMP 算法,说实话 KMP 算法确实不太好理解。不过今天我来讲一讲字符串匹配的另一种经典算法:Rabin-Karp 算法,这是一个很简单优雅的算法。 本文会由浅入深地讲明白这个算法的核心思路,先从最简单的字符串转数字讲起,然后研究一道力扣题目,到最后你就会发现 Rabin-Karp 算法使用的就是滑动窗口技巧,直接套前文讲的 滑动窗口算法框架 就出来了,根本不用死记硬背。 废话不多说了,直接上干货。 首先,我问你一个很基础的问题,给你输入一个字符串形式的正整数,如何把它转化成数字的形式?很简单,下面这段代码就可以做到: string s = "8264"; int number = ; for (int i = ; i < s.size(); i++) { // 将字符转化成数字 number = * number + (s[i] - '0'); print(number); } // 打印输出: // 8 // 82 // 826 // 8264 可以看到这个算法的核心思路就是不断向最低位(个位)添加数字,同时把前面的数字整体左移一位(乘以 10)。 为什么是乘以 10?因为我们默认探讨的是十进制数。这和我们操作二进制数的时候是一个道理,左移一位就是把二进制数乘以 2,右移一位就是除以 2。 上面这个场景是不断给数字添加最低位,那如果我想删除数字的最高位,怎么做呢?比如说我想把 8264 变成 264,应该如何运算?其实也很简单,让 8264 减去 8000 就得到 264 了。 这个 8000 是怎么来的?是 8 x 10^3 算出来的。8 是最高位的数字,10 是因为我们这里是十进制数,3 是因为 8264 去掉最高位后还剩三位数。 上述内容主要探讨了如何在数字的最低位添加数字以及如何删除数字的最高位,用R表示数字的进制数,用L表示数字的位数,就可以总结出如下公式: /* 在最低位添加一个数字 */ int number = ; // number 的进制 int R = ; // 想在 number 的最低位添加的数字 int appendVal = ; // 运算,在最低位添加一位 number = R * number + appendVal; // 此时 number = 82643 /* 在最高位删除一个数字 */ int number = ; // number 的进制 int R = ; // number 最高位的数字 int removeVal = ; // 此时 number 的位数 int L = ; // 运算,删除最高位数字 number = number - removeVal * R^(L-); // 此时 number = 264 如果你能理解这两个公式,那么 Rabin-Karp 算法就没有任何难度,算法就是这样,再高大上的技巧,都是在最简单最基本的原理之上构建的。不过在讲 Rabin-Karp 算法之前,我们先来看一道简单的力扣题目。 高效寻找重复子序列 看下力扣第 187 题「重复的 DNA 序列」,我简单描述下题目: DNA 序列由四种碱基A, G, C, T组成,现在给你输入一个只包含A, G, C, T四种字符的字符串s代表一个 DNA 序列,请你在s中找出所有重复出现的长度为 10 的子字符串。 比如下面的测试用例: 输入:s = "AAAAACCCCCAAAAACCCCCCAAAAAGGGTTT" 输出:["AAAAACCCCC","CCCCCAAAAA"] 解释:子串 "AAAAACCCCC" 和 "CCCCCAAAAA" 都重复出现了两次。 输入:s = "AAAAAAAAAAAAA" 输出:["AAAAAAAAAA"] 函数签名如下: List<String> findRepeatedDnaSequences(String s); 这道题的拍脑袋解法比较简单粗暴,我直接穷举所有长度为 10 的子串,然后借助哈希集合寻找那些重复的子串就行了,代码如下: // 暴力解法 List<String> findRepeatedDnaSequences(String s) { int n = s.length(); // 记录出现过的子串 HashSet<String> seen = new HashSet(); // 记录那些重复出现多次的子串 // 注
对于不同的查找需求场景,会采用不同的查找类型,最终采用的查找方式(查找算法)也有所不同,具体如下
今天,我们讲一讲,JS中针对 String类型的相关算法的解题技巧和一些注意事项。
给出由小写字母组成的字符串 S,重复项删除操作会选择两个相邻且相同的字母,并删除它们。
Given a string, find the length of the longest substring without repeating characters.
算法的重要性,我就不多说了吧,想去大厂,就必须要经过基础知识和业务逻辑面试+算法面试。所以,为了提高大家的算法能力,后续每天带大家做一道算法题,题目就从LeetCode上面选 !
参考资料:https://help.salesforce.com/articleView?id=managing_duplicates_overview.htm Salesforce 很重要的一个平台
滑动窗口算法(Sliding Window)是一种常用的双指针算法,被广泛应用于字符串和数组等数据结构中的子串或子数组问题,例如字符串匹配、最长子串、最小覆盖子串等问题。滑动窗口算法可以优化暴力枚举的时间复杂度,使得算法的执行效率更高。
滑动问题包含一个滑动窗口,它是一个运行在一个大数组上的子列表,该数组是一个底层元素集合。一般用来求最值问题。
这份面试资源主要包含五部分内容:数组、链表、字符串、二叉树和重要算法(如排序算法)的编程面试题,其中每部分内容我们都列出了一些最常被问到的热门问题,并且在每个题目后给出了可以参考的解决思路和代码,因为题目较多,我们没有罗列所有的方法和代码,只给出了访问地址。相信大家在掌握了这些内容后,一定可以提升实力、信心大增。
最近有小伙伴和我谈心,觉得刷算法题太难了,完全没有思路,很有挫败感,想要放弃了。想想自己也深有感触,有这些想法真都挺正常的,其实我们刷算法就是为了培养一个思考问题、解决问题的思维,这个思维养成并不是一蹴而就的,而是循序渐进的。
在信息论、语言学和计算机科学中,Levenshtein distance是用于测量两个字符串之间差异的字符串度量。非正式的说就是两个单词之间的Levenshtein distance是将一个单词更改为另一个单词所需的单字符编辑(插入,删除或替换)的最小步骤。
所谓左右指针,就是两个指针相向而行或者相背而行;而所谓快慢指针,就是两个指针同向而行,一快一慢。
从字符串的定义到库函数的使用原则,从各种反转到KMP算法,相信大家应该对字符串有比较深刻的认识了。
在示例代码中,str是一个字符串的变量名称,hello world则是该字符串的值,字符串的长度为11,该字符串的表示如下图所示:
字符串 如果想让这套题目有意义,就不要申请额外空间。 344.反转字符串 双指针 // 时间复杂度O(n),执行n/2次交换 // 空间复杂度O(1) class Solution { public: void reverseString(vector<char>& s) { int n = s.size(); for(int left = 0,right = n-1;left <= right;left++,right--){ swap(
其实我们已经学习了十天的字符串了,从字符串的定义到库函数的使用原则,从各种反转到KMP算法,相信大家应该对字符串有比较深刻的认识了。
注册账号是进行网络冲浪的第一步操作,而拥有一个具有个性且独一无二的用户昵称是非常重要的,很多人在填写昵称时,常常会看到 此昵称已存在 的提示,系统是如何快速知道当前昵称是否存在呢?总不能挨个去遍历对比吧,这时候就需要我们本文中的主角: 布隆过滤器
我们可以利用 hash 来判断不重复子串。如果 hash 表中存在该字符串,就进入下次循环;如果不存在,就放入集合中然后在再移动右指针。
当搜索一个键时,哈希表使用相同的哈希函数来查找对应的桶,并只在特定的桶中进行搜索。
题目要求找出给定字符串中不含重复字符的最长子串,我们可以采用暴力穷举的方式,得到字符串中的所有子串,然后一一判断不重复子串的长度,最后返回最长子串的长度即可,比如:
在任何一步中,如果最小或者最大字符不止一个,你可以选择其中任意一个,并将其添加到结果字符串。
贪心算法适用于一些具有贪心选择性质的问题,这些问题的最优解可以通过一系列局部最优解来达到。通常情况下,贪心算法的效率较高,因为它不需要进行全局搜索,而是通过局部选择来逐步构建解决方案。
Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000.
1.把二元查找树转变成排序的双向链表(树) 题目: 输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表。 要求不能创建任何新的结点,只调整指针的指向。 10 / / 6 14 / / / / 4 8 12 16 转换成双向链表 4=6=8=10=12=14=16。 首先我们定义的二元查找树 节点的数据结构如下: struct BSTreeNode { int m_nValue; // value of node BSTreeNode *m_pLeft; // left child of node
通常我会使用常规的、显而易见的 PHP 函数来编写代码来解决相应的问题。但对于其中一些问题,我遇到了特别提高性能的替代解决方案。
97. 交错字符串 给定三个字符串 s1、s2、s3,请你帮忙验证 s3 是否是由 s1 和 s2 交错 组成的。 两个字符串 s 和 t 交错 的定义与过程如下,其中每个字符串都会被分割成若干 非空 子字符串: s = s1 + s2 + … + sn t = t1 + t2 + … + tm |n - m| <= 1 交错 是 s1 + t1 + s2 + t2 + s3 + t3 + … 或者 t1 + s1 + t2 + s2 + t3 + s3 + … 注意:a + b 意味着字符串 a 和 b 连接。
Google Jam大赛是谷歌举办的一年一届的在线答算法题的的比赛。初赛比赛时长27小时,一共有5道算法题,总分100分,获得分数30分和以上者,就能晋级下一轮比赛。在这27小时内,选手可以多次进入jam的比赛链接,查看题目和提交代码,每道题可以提交多次。提交后,页面会实时反馈代码运行测试用例结果(通过/未通过),不过不会展示测试结果集。参加Jam的选手,进入前一千名有T恤发放;前三名奖励现金,一般参加人数达数万人,基本没有拿奖的可能了。我在赛事开始前看到了GDG公众号关于JAM的赛事信息推送,于是抱着闲着也是闲着,不如试试水的心态报名参加2020年的Jam。
很多人做leetcode题目找不到方向,或者说很难持之以恒,我这里推荐一种方法,从简单难度开始刷,刷完这个标签的简单难度,再换一个标签,这样循序渐进,把做题的量慢慢提高,还有难度逐渐加大。对于初学者,最重要是趁热打铁,而不是东打一枪西放一炮,趁热打铁才能形成做题的思路。
前言 在🗡指offer中有这样一句话,“对于初级程序员,我一般会偏向考查算法和数据结构,看应聘者的基本功;对于高级程序员,我会多关注专业技能和项目经验”,这也是我为何多数博客都是分享算法知识的原因,在我看来,如果盲目的去追求小demo,可能远不如有一个良好的算法,数据结构基础重要。 这是我第三遍刷🗡指offer的感触,持续更新,也会放到免费的专栏中,感兴趣的朋友可以订阅一下,博主能力有限,如果在文中有错误,还请不吝赐教,在评论区指出,我会一一解答 分类 数组 面试题3——数组中重复的数字 面试题4
数据结构和算法 链表 链表,常见的面试题有写一个链表中删除一个节点的算法、单链表倒转、两个链表找相交的部分,这个一般必须得完全无误的情况下写出来; 给出两个链表的头结点,找出这两个链表的交点。 java 中数组和链表的区别,各自优势 如何设计拥有高效的随机读取能力的的链表(跳表) 设计跳表,跳表插入开销,跳表随机读取过程 给你一个单向链表,给这个链表做K反转,例如 k=3 1 -> 2 -> 3 -> 4 -> 5 -> 6 反转后为:3 -> 2 -> 1 -> 6 -> 5 -> 4 链表长度保证为K的
很多人觉得动态规划很难,甚至认为面试出动态规划题目是在为难候选人,这可能产生一个错误潜意识:认为动态规划不需要掌握。
空间复杂度为O(∣Σ∣),其中 Σ 表示字符集(即字符串中可以出现的字符),∣Σ∣ 表示字符集的大小。
List是python中的基本数据结构之一,和Java中的ArrayList有些类似,支持动态的元素的增加。list还支持不同类型的元素在一个列表中,
东京奥运会圆满收官!当然我自己也将迎来留学前的最后准备,所以更新速度可能还是会比较慢……但还好,大部分的内容都已经在之前写的差不多了,也希望最后这几篇我也能够尽快更完,当然也希望大家可以谅解~
算法的重要性,我就不多说了吧,想去大厂,就必须要经过基础知识和业务逻辑面试+算法面试。所以,为了提高大家的算法能力,这个公众号后续每天带大家做一道算法题,题目就从LeetCode上面选 !
问题描述 百度面试题: 搜索引擎会通过日志文件把用户每次检索使用的所有检索串都记录下来,每个查询串的长度为1-255字节。 假设目前有一千万个记录(这些查询串的重复度比较高,虽然总数是1千万,但如果除去重复后,不超过3百万个。一个查询串的重复度越高,说明查询它的用户越多,也就是越热门。),请你统计最热门的10个查询串,要求使用的内存不能超过1G。
这次的题目是找出字符串中最长不重复子串,一开始还以为跟最长匹配子串类似,需要用到动态规划呢,结果还是自己想太多了,偷看了一眼Tag,才发现只需要用hashmap和两个指针就能搞定。 算法的主要思想是:初始化两个指针head和tail,分别指向字符串初始位置0,并初始化一个hashmap,key为考察中的字符,value为对应字符所在位置。然后一个while循环,直至tail到达字符串尾部,在循环的每一步,首先会检查s[tail]是否存在于hashmap中,如果没有,则插入,否则找出s[tail]之前出现过的
周末你带着女朋友去电影院看电影,女朋友问你,咱们现在坐在第几排啊?电影院里面太黑了,看不清,没法数,现在你怎么办?别忘了你是程序员,这个可难不倒你,递归就开始排上用场了。 于是你就问前面一排的人他是第几排,你想只要在他的数字上加一,就知道自己在哪一排了。但是,前面的人也看不清啊,所以他也问他前面的人。就这样一排一排往前问,直到问到第一排的人,说我在第一排,然后再这样一排一排再把数字传回来。直到你前面的人告诉你他在哪一排,于是你就知道答案了。 我们用递推公式将它表示出来就是这样的:
本课程重点介绍科技公司在面试时经常出现的计算机科学问题,其中包括时间复杂度、哈希表、二进制树搜索,以及 MIT「算法设计与分析」(MIT 6.046)课程中会出现的内容。但是,大部分时间都会专注于你不会在课堂上学到的内容,例如刁钻的按位逻辑和解决问题的技巧。
一个有向图(或有向图)是一组顶点和一组有向边,每条边连接一个有序对的顶点。我们说一条有向边从该对中的第一个顶点指向该对中的第二个顶点。对于 V 个顶点的图,我们使用名称 0 到 V-1 来表示顶点。
领取专属 10元无门槛券
手把手带您无忧上云