——写在前面,复习算法一段时间了,在此记录一下自己写过的算法代码,算是做个总结,供自己以后回顾。
43.字符串相乘
给定两个以字符串形式表示的非负整数 num1
和 num2
,返回 num1
和 num2
的乘积,它们的乘积也表示为字符串形式。
示例 1:
输入: num1 = "2", num2 = "3"
输出: "6"
示例 2:
输入: num1 = "123", num2 = "456"
输出: "56088"
思路:大数相乘,用一个int数组存每一位的相乘数,像小学时学的乘法运算那样算
class Solution {
public String multiply(String num1, String num2) {
if(num1.equals("0")||num2.equals("0"))
return "0";
int len1 = num1.length();
int len2=num2.length();
int res_len=len1+len2;
int res[]=new int [res_len];
for(int i=len1-1;i>=0;i--){
int n1=num1.charAt(i)-48;
int tmp=0;
for(int j=len2-1;j>=0;j--){
int n2=num2.charAt(j)-48;
res[i+j+1]=n1*n2+res[i+j+1]+tmp;
tmp =res[i+j+1]/10;
res[i+j+1]=res[i+j+1]%10;
}
res[i]+=tmp;
}
StringBuilder sb=new StringBuilder();
int flag=1;
for(int i=0;i
322. 零钱兑换
给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1
。
class Solution {
public int coinChange(int[] coins, int amount) {
int size=coins.length;
int dp[]=new int[amount+1];
//0x3F3F3F表示一个很大的数,dp[j]表示找零金额为j时的最少硬币数
Arrays.fill(dp,0x3F3F3F);
dp[0]=0;
//遍历i种硬币,新的最少硬币数会覆盖旧的最少硬币数
for(int i=0 ;i
62. 不同路径
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。
问总共有多少条不同的路径?
输入: m = 3, n = 2
输出: 3
解释:
从左上角开始,总共有 3 条路径可以到达右下角。
1. 向右 -> 向右 -> 向下
2. 向右 -> 向下 -> 向右
3. 向下 -> 向右 -> 向右
考察:dp动态规划,dp[i][j]=dp[i-1][j]+dp[i][j-1]
class Solution {
public int uniquePaths(int m, int n) {
if(m==1&&n==1)
return 1;
int dp[][]=new int[m][n];
for(int i=1;i
69. x 的平方根
实现 int sqrt(int x)
函数。
计算并返回 x 的平方根,其中 x 是非负整数。
由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。
示例 2:
输入: 8
输出: 2
说明: 8 的平方根是 2.82842...,
由于返回类型是整数,小数部分将被舍去。
考察:二分搜索
class Solution {
public int mySqrt(int x) {
int i=1,j=x;
while(i<=j)
{
int mid=(i+j)/2;
if(midx/mid)
j=mid-1;
else return mid;
}
return j;
}
}
//另一种做法 return (int)Math.sqrt(x);
94. 二叉树的中序遍历
给定一个二叉树,返回它的中序 遍历。
示例:
输入: [1,null,2,3]
1
\
2
/
3
输出: [1,3,2]
考察:有两种做法,递归很简单,迭代复杂点
class Solution {
List res=new ArrayList();
public void search(TreeNode root){ //这是递归做法
if(root==null)
return;
if(root.left!=null)
search(root.left);
res.add(root.val);
if(root.right!=null)
search(root.right);
}
public List inorderTraversal(TreeNode root) {
search(root);
return res;
}
}
67. 二进制求和
给定两个二进制字符串,返回他们的和(用二进制表示)。
输入为非空字符串且只包含数字 1
和 0
。
示例 1:
输入: a = "11", b = "1"
输出: "100"
考察:math,相加的进位
class Solution {
public String addBinary(String a, String b) {
int aLen=a.length()-1;
int bLen=b.length()-1;
int m=0;
int n=0;
StringBuilder res=new StringBuilder();//用数组来存结果也可以,然后把数组转化为String,最后如果有进位则在结果前加个"1"
while(aLen>=0&&bLen>=0){
int tmp=a.charAt(aLen)-'0'+b.charAt(bLen)-'0'+n;
m=tmp%2;
n=tmp/2;
res.insert(0,String.valueOf(m));
aLen--;
bLen--;
}
while(aLen>=0){
int tmp=a.charAt(aLen)-'0'+n;
m=tmp%2;
n=tmp/2;
res.insert(0,String.valueOf(m));
aLen--;
}
while(bLen>=0){
int tmp=b.charAt(bLen)-'0'+n;
m=tmp%2;
n=tmp/2;
res.insert(0,String.valueOf(m));
bLen--;
}
if(n>0){
res.insert(0,"1");
}
return res.toString();
}
}
49. 字母异位词分组
给定一个字符串数组,将字母异位词组合在一起。字母异位词指字母相同,但排列不同的字符串。
示例:
输入: ["eat", "tea", "tan", "ate", "nat", "bat"]
,
输出:
[
["ate","eat","tea"],
["nat","tan"],
["bat"]
]
考察:HashMap
class Solution {
public List> groupAnagrams(String[] strs) {
Map>map=new HashMap<>();
List>result=new ArrayList<>();
if(strs.length==0)
return result;
for(String s:strs){
char[] tmp=s.toCharArray();
Arrays.sort(tmp);
String keyStr=new String(tmp);
if(!map.containsKey(keyStr))
{
List item=new ArrayList();
item.add(s);
map.put(keyStr,item);
result.add(item);
}
else
map.get(keyStr).add(s);
}
return result;
}
}
206. 反转链表
反转一个单链表。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
考察:递推遍历链表
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode reverseList(ListNode head) {
if(head==null)
return null;
ListNode cur=head.next;
ListNode next;
head.next=null;
while(cur!=null){
next=cur.next;
cur.next=head;
head=cur;
cur=next;
}
return head;
}
}
23. 合并K个排序链表
合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。
示例:
输入:
[
1->4->5,
1->3->4,
2->6
]
输出: 1->1->2->3->4->4->5->6
考察:两指针,归并
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode mergeTwoList(ListNode first,ListNode two){
if(first==null)
return two;
if(two==null)
return first;
ListNode node=new ListNode(0);
if(first.val0){
begin=0;
while(begin
24. 两两交换链表中的节点
给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
示例:
给定1->2->3->4
, 你应该返回2->1->4->3
.
考察:链表
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode swapPairs(ListNode head) {
if(head==null||head.next==null)
return head;
ListNode second=head.next;
ListNode third=second.next;
second.next=head;
head.next=swapPairs(third);
return second;
}
}
98、验证是否是二叉搜索树:给定一个二叉树,判断其是否是一个有效的二叉搜索树。
考察:二叉搜索树的中序遍历是递增(或递减)的,通过递归进行中序遍历
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
boolean isFirst=true;
int lastval;
public boolean isValidBST(TreeNode root) {
if(root ==null){
return true;
}
if(!isValidBST(root.left)){
return false;
}
if(!isFirst&&lastval>=root.val)
return false;
isFirst=false;
lastval=root.val;
if(!isValidBST(root.right)){
return false;
}
return true;
}
}
22. 括号生成
给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合。
例如,给出 n = 3,生成结果为:
[
"((()))",
"(()())",
"(())()",
"()(())",
"()()()"
]
考察:深度优先搜索(dfs),栈,括号匹配
class Solution {
int left,right; //分别记录'('和')'的剩余数量
LinkedList stack=new LinkedList<>(); //栈,存储左括号'('
char item[]; //记录每种情况的括号排列
int len;
List result=new LinkedList<>();
public void dfs(int depth){
if(depth==len-1){ //遍历到最后一个括号,一定是')'
item[len-1]=')';
String tmp=new String(item);
result.add(tmp);
}
else {
if(left!=0){
stack.addFirst('(');
item[depth]='(';
left--;
dfs(depth+1);
left++;//回溯
stack.poll();
}
if(right!=0&&!stack.isEmpty()){ //当')'剩余数不为0且栈中有'('时,可以取出一个左括号匹配
stack.poll();
item[depth]=')';
right--;
dfs(depth+1);
right++; //回溯
stack.addFirst('(');
}
}
}
public List generateParenthesis(int n) {
left=n-1;
right=n;
len=2*n;
item=new char[n*2];
item[0]='(';
stack.addFirst('(');
dfs(1);
return result;
}
}
127. 单词接龙
给定两个单词(beginWord 和 endWord)和一个字典,找到从 beginWord 到 endWord 的最短转换序列的长度。转换需遵循如下规则:
说明:
考察:广度优先搜索,最短路径,注意:set的查找速度比list快很多
class Solution {
public int ladderLength(String beginWord, String endWord, List wordList) {
if(!wordList.contains(endWord))
return 0;
int level=1,curnum=1,nextnum=0;
LinkedListq=new LinkedList();
Setvisited=new HashSet();
q.add(beginWord);
visited.add(beginWord);
Set dic=new HashSet(wordList);
while(!q.isEmpty()){
String str=q.poll();
curnum--;
int len=str.length();
for(int i=0;i
12、实现strStr():
给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在,则返回 -1。
考察:KMP算法
class Solution {
public int strStr(String haystack, String needle) {
char []nee=needle.toCharArray();
char []hay=haystack.toCharArray();
int l1=hay.length;
int l2=nee.length;
if(l2==0)
return 0;
int next[]=new int[l2];
next[0]=-1;//计算next[]数组,当没有公共前后缀时,next[i]=-1;
for(int i=1;i=0)
t=next[t];
if(nee[t+1]==nee[i])
next[i]=t+1;
else
next[i]=-1;
}
int i=0,j=0;//遍历查找,时间复杂度为m+n
while(i
12. 整数转罗马数字
罗马数字包含以下七种字符: I
, V
, X
, L
,C
,D
和 M
。
例如, 罗马数字 2 写做 II
,即为两个并列的 1。12 写做 XII
,即为 X
+ II
。 27 写做 XXVII
, 即为 XX
+ V
+ II
。
给定一个整数,将其转为罗马数字。输入确保在 1 到 3999 的范围内。
考察:二维数组,math,指针遍历字符串。
class Solution {
public String intToRoman(int num) {
String str=String.valueOf(num);
String [][] arr={{"I","II","III","IV","V","VI","VII","VIII","IX"},
{"X","XX","XXX","XL","L","LX","LXX","LXXX","XC"},
{"C","CC","CCC","CD","D","DC","DCC","DCCC","CM"},
{"M","MM","MMM"}
};
int len=str.length();
StringBuilder sb=new StringBuilder();
for(int i=0;i
13. 罗马数字转整数
罗马数字包含以下七种字符:I
, V
, X
, L
,C
,D
和 M
。
给定一个罗马数字,将其转换成整数。输入确保在 1 到 3999 的范围内。
考察:swich分支,math
class Solution {
public int romanToInt(String s) {
int index[]={1,5,10,50,100,500,1000};
char[] arr=s.toCharArray();
int len=arr.length;
int last=index[getIndex(arr[0])];
int result=0;
if(len==1)
return last;
int tmp=0;
for(int i=1;i
125. 验证回文串
给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。
考察:两指针
class Solution {
public boolean isPalindrome(String s) {
if(s==null||s.length()==0)
return true;
s=s.toLowerCase();
int len=s.length();
char[] arr=new char[len];
int j=0;
for(int i=0;i='a'&&tmp<='z'||tmp>='0'&&tmp<='9')
arr[j++]=tmp;
}
int low=0,high=j-1;
while(low
88. 合并两个有序数组
给定两个有序整数数组 nums1 和 nums2,将 nums2 合并到 nums1 中,使得 num1 成为一个有序数组。
考察:两指针,归并,归并排序的归并部分思路
class Solution {
public void merge(int[] nums1, int m, int[] nums2, int n) {
int []asis=new int[m];//辅助数组,把nums1中的m个数拷贝出来
for(int i=0;i
73、矩阵置零
给定一个 m x n 的矩阵,如果一个元素为 0,则将其所在行和列的所有元素都设为 0。请使用原地算法。
考察:数组,先标记再最后置零
class Solution {
public void setZeroes(int[][] matrix) {
int rlen=matrix.length;
int clen=matrix[0].length;
boolean row[]=new boolean[rlen];
boolean col[]=new boolean[clen];
for(int i=0;i
27. 移除元素
给定一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,返回移除后数组的新长度。
考察:快排中swap的部分
class Solution {
public int removeElement(int[] nums, int val) {
int len=nums.length;
int right=len-1;
int i=0;
while(i<=right){
if(nums[i]==val){
nums[i]=nums[right--];
}
else i++;
}
return right+1;
}
}
16、有效的数字:
验证给定的字符串是否为数字。
例如:"0"
=> true
" 0.1 "
=> true
"abc"
=> false
"1 a"
=> false
"2e10"
=> true
考察:math,一个数字是否合法,指针遍历字符串,细节
class Solution {
public boolean isNumber(String s) {
s=s.trim();
int len=s.length();
if(len==0||s==null)
return false;
int i=0;
boolean hasDot=false;
boolean hasE=false;
boolean hasDigit=false;
if(s.charAt(i)=='e'||s.charAt(len-1)=='e'||s.charAt(len-1)=='+'||s.charAt(len-1)=='-')
return false;
if(s.charAt(i)=='-'||s.charAt(i)=='+'){
i++;
}
while(i='0'&&s.charAt(i)<='9'){
i++;
hasDigit=true;
}
else if(s.charAt(i)=='e'&&hasE==false&&hasDigit==true){
i++;
hasE=true;
if(s.charAt(i)=='+'||s.charAt(i)=='-'){
i++;
}
}
else if(s.charAt(i)=='.'&&hasDot==false&&hasE==false){
i++;
hasDot=true;
}
else return false;
}
if(hasDigit==false)
return false;
return true;
}
}
1、给定一个没有重复数字的序列,返回其所有可能的全排列。
考察:深度优先搜索(dfs)
class Solution {
int []visit;
List> result;
int len;
int [] Allnums;
int [] result_arr;
void dfs(int depth){
if(depth==len){
List item=new ArrayList<>();
int arrLen=result_arr.length;
for(int j=0;j> permute(int[] nums) {
Allnums=nums;
result=new ArrayList<>();
len=nums.length;
result_arr=new int[len];
visit=new int[len];
dfs(0);
return result;
}
}
2、给定一个可包含重复数字的序列,返回所有不重复的全排列。
考察:深度优先搜索(dfs)
class Solution {
int [] input;
int len;
int [] result;
List > output;
Map map;
Set set;
int keylen;
void dfs(int depth){
if(depth==len){
List AddToOutput=new ArrayList();
for(int k=0;k=1){
result[depth]=input[i];
map.put(input[i], value-1);
dfs(depth+1);
map.put(input[i], value);
}
}
}
public List> permuteUnique(int[] nums) {
len=nums.length;
map=new HashMap();
for(int i=0;iit=set.iterator();
int cnt=0;
while(it.hasNext()){
input[cnt++]=it.next();
}
result=new int[len];
output=new ArrayList<>();
dfs(0);
return output;
}
}
3、求最大子序和:给定一个整数数组 nums
,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
考察:动态规划
class Solution {
public int maxSubArray(int[] nums) {
int len=nums.length;
int []sum=new int[len];
int []maxsubsum=new int[len];
sum[0]=nums[0];
maxsubsum[0]=nums[0];
for(int i=1;i
5、二叉树的层次遍历
考察:广度优先搜索(bfs)
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public List> levelOrder(TreeNode root) {
LinkedList q=new LinkedList();
List > result=new LinkedList<>();
if(root==null)
return result;
List first=new LinkedList();
first.add(root.val);
result.add(first);
q.offer(root);
int curnum=1;
int nextnum=0;
List item=new LinkedList();
while(!q.isEmpty()){
TreeNode t=q.poll();
curnum--;
if(t.left!=null){
item.add(t.left.val);
q.offer(t.left);
nextnum++;
}
if(t.right!=null){
item.add(t.right.val);
q.offer(t.right);
nextnum++;
}
if(curnum==0){
curnum=nextnum;
nextnum=0;
if(!item.isEmpty())
{
result.add(item);
item=new LinkedList();
}
}
}
return result;
}
}
6、合并区间:给出一个区间的集合,请合并所有重叠的区间
考察:排序(快速排序),归并思路
/**
* Definition for an interval.
* public class Interval {
* int start;
* int end;
* Interval() { start = 0; end = 0; }
* Interval(int s, int e) { start = s; end = e; }
* }
*/
class Solution {
public void quickSort(Interval[] input,int low,int high){
if(low>=high)
return ;
int v=input[low].start;
int left=low,right=high;
int i=low+1;
while(i<=right){
int tmp=input[i].start;
if(tmp>v){
Interval tmp2=input[i];
input[i]=input[right];
input[right--]=tmp2;
}
else if(tmp merge(List intervals) {
List res=new ArrayList();
int len=intervals.size();
if(len==0)
return res;
Interval [] input= new Interval[len];
intervals.toArray(input);
quickSort(input,0,len-1);
Interval item=input[0];
for(int i=1;iitem.end)
{
res.add(item);
item=tmp;
}
else{
item.end=Math.max(item.end, tmp.end);
}
}
res.add(item);
return res;
}
}
7、插入区间:
给出一个无重叠的 ,按照区间起始端点排序的区间列表。
在列表中插入一个新的区间,你需要确保列表中的区间仍然有序且不重叠(如果有必要的话,可以合并区间)。
考察:归并思路
/**
* Definition for an interval.
* public class Interval {
* int start;
* int end;
* Interval() { start = 0; end = 0; }
* Interval(int s, int e) { start = s; end = e; }
* }
*/
class Solution {
public List insert(List intervals, Interval newInterval) {
List res=new ArrayList();
int len=intervals.size();
if(len==0){
res.add(newInterval);
return res;
}
int l=newInterval.start;
int r=newInterval.end;
boolean insert=false;
for(int i=0;i=l)
l=tmp.start;
if(tmp.start<=r&&tmp.end>=r)
{
r=tmp.end;
continue;
}
if(tmp.start>r&&!insert){
res.add(new Interval(l,r));
insert=true;
}
if(tmp.start>r||tmp.end
8、无重复字符的最大字串:给定一个字符串,找出不含有重复字符的最长子串的长度
考察:哈希,ascii
class Solution {
public int lengthOfLongestSubstring(String s) {
int [] hash=new int[256];
Arrays.fill(hash, -1);
int maxLen=0,left=-1;
int len=s.length();
for(int i=0;i
9、字符串转整数:实现 atoi
,将字符串转为整数。
考察:指针遍历字符串的每个字符,math
class Solution {
public int myAtoi(String str) {
if(str.isEmpty())
return 0;
int flag=1,result=0,i=0,len=str.length();
while(i='0'&&str.charAt(i)<='9'){
if(result>Integer.MAX_VALUE/10||(result==Integer.MAX_VALUE/10&&str.charAt(i)>'7'))
return (flag==1)?Integer.MAX_VALUE:Integer.MIN_VALUE;
result=result*10+(str.charAt(i++)-'0');
}
return flag*result;
}
}
10、三数之和:
给定一个包含 n 个整数的数组 nums
,判断 nums
中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
考察:2个指针设定,排序
class Solution {
public List> threeSum(int[] nums) {
List>result=new LinkedList<>();
int len=nums.length;
Arrays.sort(nums);
for(int i=0;i0&&nums[i]==nums[i-1])
continue;
int a=nums[i];
int left=i+1;
int right=len-1;
while(lefti+1&&nums[left]==nums[left-1])
left++;
else if(a+nums[left]+nums[right]>0){
right--;
}
else if(a+nums[left]+nums[right]<0){
left++;
}
else{
Listitem=new LinkedList<>();
item.add(nums[i]);
item.add(nums[left]);
item.add(nums[right]);
result.add(item);
left++;
right--;
}
}
}
return result;
}
}
11、有效的括号:
给定一个只包括 '('
,')'
,'{'
,'}'
,'['
,']'
的字符串,判断字符串是否有效。
考察:栈
class Solution {
public boolean isValid(String s) {
LinkedList stack=new LinkedList();
int len=s.length();
for(int i=0;i
13、合并两个有序链表:
将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例:
输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4
考察:递归,归并思路
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode res=new ListNode(0);
if(l1==null&&l2==null)
return null;
else if(l1!=null&&l2!=null){
if(l1.val
2、两数相加:
给定两个非空链表来表示两个非负整数。位数按照逆序方式存储,它们的每个节点只存储单个数字。将两数相加返回一个新的链表。
你可以假设除了数字 0 之外,这两个数字都不会以零开头。
示例:
输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807
考察:递归
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode add(ListNode l1,ListNode l2,int jin){
if(l1==null&&l2==null&&jin==0)
return null;
if(l1==null)
l1=new ListNode(0);
if(l2==null)
l2=new ListNode(0);
ListNode res=new ListNode(0);
int sum=l1.val+l2.val+jin;
res.val=sum%10;
res.next=add(l1.next,l2.next,sum/10);
return res;
}
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
return add(l1,l2,0);
}
}
15、Pow(x,n):
实现 pow(x, n) ,即计算 x 的 n 次幂函数。
考察:分治,把线性复杂度将为logn
class Solution {
public double myPow(double x, int n) {
double res=1.0;
if(x==0)
return 0;
else if(n==-1)
return 1.0/x;
else if(n==1)
return x;
else if(n==0)
return 1.0;
else {
for(int i=n;i!=0;i/=2,x*=x){
if(i%2!=0)
res*=x;
}
return n<0?1.0/res:res;
}
}
}