数组
1 二维数组中的查找
题目描述
在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
思路
由于数组从左至右,从上至下都是有序的,可以先判断每行最右边的数字即每行最大的数字是否小于目标值,如果小于的话则跳到下一行,如果在下一行没有找到则继续跳到下一行,依次类推。
其中在每一行使用二分查找查找目标值。
public class Solution {
public boolean Find(int target, int [][] array) {
//如果数组为空返回false
if(array.length==0||array[0].length==0)
return false;
int row=0;//从第一行开始
while(row<array.length){//循环到最后一行
if(array[row][array[0].length-1]<target){//如果该行最后一列小于目标值
row++;//跳到下一行
}
else {//在行中使用二分查找
int low=0;
int high=array[0].length-1;
while(low<=high){
int mid=low+(high-low)/2;
if(array[row][mid]<target)
low=mid+1;
else if(array[row][mid]>target)
high=mid-1;
else
return true;
}//如果没找到 跳到下一行 不然会无限循环
row++;
}
}
return false;
}
}
2 数组中重复的数字
题目描述
在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。
思路
使用哈希表,判断当前遍历的元素是否已存在,若存在返回true。
public class Solution {
public boolean duplicate(int numbers[],int length,int [] duplication) {
if(numbers!=null){
HashMap<Integer,Integer> map=new HashMap<>();
for(int num:numbers){
if(map.containsKey(num)){
duplication[0]=num;
return true;
}else
map.put(num,1);
}
duplication[0]=-1;
return false;
}
}
3 构建乘积数组
题目描述
给定一个数组A[0,1,…,n-1],请构建一个数组B[0,1,…,n-1],其中B中的元素B[i]=A[0]A[1]…*A[i-1]A[i+1]…*A[n-1]。不能使用除法。
思路
按照题目描述构建算法即可。
public class Solution {
public int[] multiply(int[] A) {
int[] B=new int[A.length];//长度和A一样
for(int i=0;i<A.length;i++){//依次计算乘积并赋值
int mul=1;
for(int j=0;j<i;j++)//计算0-i-1的乘积
mul*=A[j];
for(int j=i+1;j<A.length;j++)//计算i+1到n-1的乘积
mul*=A[j];
B[i]=mul;//赋值
}
return B;
}
}
字符串
1 替换空格
题目描述
请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。
思路
构建一个stringbuffer,如果遇到空格则附加%20,否则附加原字符。
public class Solution {
public String replaceSpace(StringBuffer str) {
StringBuffer sb=new StringBuffer();
for(int i=0;i<str.length();i++){
if(str.charAt(i)!=' ')
sb.append(str.charAt(i));
else
sb.append("%20");
}
return sb.toString();
}
}
2 正则表达式匹配
题目描述
请实现一个函数用来匹配包括.
和*
的正则表达式。模式中的字符’.‘表示任意一个字符,而’*'表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串aaa
与模式a.a
和ab*ac*a
匹配,但是与aa.a
和ab*a
均不匹配
思路
利用递归判断,定义两个指针分别遍历字符串和匹配字符串,若可以同时到达末尾说明可以完全匹配,否则说明不能完全匹配。
public class Solution {
public boolean match(char[] str, char[] pattern){
//任意一个为空,则匹配失败
if(str==null||pattern==null)
return false;
return match(str,0,pattern,0);
}
public boolean match(char[] str, int s,char[] pattern,int p){
//如果字符串和匹配字符串都到达了末尾,则说明匹配成功
if(s==str.length&&p==pattern.length)
return true;
//如果字符串未遍历结束,但匹配字符串已结束,匹配失败
if(s<str.length&&p==pattern.length)
return false;
//如果匹配字符串的下一个字符是*
if(p<pattern.length-1&&pattern[p+1]=='*'){
//如果当前字符串字符和匹配字符串字符相同或者匹配字符为.
if(s<str.length&&(str[s]==pattern[p]||pattern[p]=='.'))
return match(str, s+1, pattern, p)//.*可以匹配多个字符 如aa匹配a*
||match(str, s, pattern, p+2);//忽略当前匹配字符串的2个字符 如a不匹配b*,可跳过
else
return match(str, s, pattern, p+2);//匹配失败
}
if(s<str.length&&(str[s]==pattern[p]||pattern[p]=='.')){
return match(str,s+1,pattern,p+1);
}
return false;
}
}
3 字符流中第一个不重复的字符
题目描述
请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g"。当从该字符流中读出前六个字符“google"时,第一个只出现一次的字符是"l"。
输出描述
如果当前字符流没有存在出现一次的字符,返回#字符。
思路
定义一个ArrayList集合存储输入流的字符,一个哈希表记录各字符的出现次数,遍历当前集合返回第一个出现次数为1的字符,如果没有就返回#
。
import java.util.*;
public class Solution {
//Insert one char from stringstream
HashMap<Character,Integer> map=new HashMap<>();
ArrayList<Character> list=new ArrayList<>();
public void Insert(char ch){
if(map.containsKey(ch))//如果存在就加一
map.put(ch,map.get(ch)+1);
else//不存在就放入map,并赋初值1
map.put(ch,1);
list.add(ch);//保存到集合中
}
//return the first appearence once char in current stringstream
public char FirstAppearingOnce(){
//遍历集合返回在哈希表中出现次数为1的字符
for(char c:list){
if(map.get(c)==1)
return c;
}
return '#';//如果没有则返回#
}
}
4 表示数值的字符串
题目描述
请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+100",“5e2”,"-123",“3.1416"和”-1E-16"都表示数值。 但是"12e",“1a3.14”,“1.2.3”,"±5"和"12e+4.3"都不是。
思路
^
表示以…开头
[+-]
表示有0或1个正负号
[0-9]*
表示任意个数字
(\\.[0-9]*)?
表示0或1个 (小数点+任意个数字) 如.1
, .123
([eE][+-]?[0-9]+)?
表示0或1个( e/E 0或1个正负号 一或多个数字) 如e+1
, e-12
,e2
$
表示以…结尾
public class Solution {
public boolean isNumeric(char[] str) {
String s="^[+-]?[0-9]*(\\.[0-9]*)?([eE][+-]?[0-9]+)?$";
String line=new String(str);
return line.matches(s);
}
}
链表
1 从尾到头打印链表
题目描述
输入一个链表,按链表从尾到头的顺序返回一个ArrayList。
思路
先遍历链表存储值到集合中,再对换链表前半部分和后半部分的值
import java.util.ArrayList;
public class Solution {
public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
ArrayList<Integer> list=new ArrayList<>();
while(listNode!=null){//遍历链表,存值到集合
list.add(listNode.val);
listNode=listNode.next;
}
//将集合前后部分的值对换
for(int i=0;i<list.size()/2;i++){
int temp=list.get(i);
list.set(i,list.get(list.size()-1-i));
list.set(list.size()-1-i,temp);
}
return list;
}
}
2 链表中环的节点入口
题目描述
给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。
思路
设链表入口到环入口的距离为a,设两个快慢指针slow和fast,slow每次一步,fast两步,相遇时距离环入口距离为b,剩下环距离为c。
由于fast的距离是slow的2倍,因此fast的路程a+n(b+c)+b是slow的路程a+b的2倍,化简得到a=(n-1)b+c,所以相遇时将如果同时从相遇点和链表入口出发一定在环入口相遇。
public class Solution {
public ListNode EntryNodeOfLoop(ListNode pHead){
//如果链表长度小于2个,不可能存在环
if(pHead==null||pHead.next==null)
return null;
//定义快慢指针
ListNode slow=pHead;
ListNode fast=pHead;
while(fast.next!=null){//fast的下一个不为空
slow=slow.next;//slow走一步
fast=fast.next.next;//fast走两步
if(slow==fast){//相遇
fast=pHead;//fast从环入口开始
while(slow!=fast){//直到相遇
slow=slow.next;
fast=fast.next;
}
return slow;//返回环入口
}
}
return null;//不存在环
}
}
3 删除链表中重复的结点
题目描述
在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5
思路
添加一个头结点便于遍历,定义前后两个指针,让last.next指针只需非重复数字的结点。
import java.util.*;
public class Solution {
public ListNode deleteDuplication(ListNode pHead){
ListNode head=new ListNode(-1);//定义头结点
head.next=pHead;
ListNode pre=head;//定义前指针
ListNode last=pre.next;//定义后指针
while(last!=null){//后指针不为空
if(last.next!=null&&last.val==last.next.val){//如果后指针的下一个和当前相同
while(last.next!=null&&last.next.val==last.val)//遍历直到后指针的下一个是非重复数
last=last.next;
pre.next=last.next;//前指针的下一个是非重复数,跳过重复数
last=last.next;//更新后指针
}else{//没遍历到重复数时前后指针都跳到下一个
pre=pre.next;
last=pre.next;
}
}
return head.next;
}
}
wait