目前刷的一些算法总结
1.判断链表中是否有环
题目描述:判断给定的链表中是否有环。如果有环则返回true,否则返回false。 你能给出空间复杂度O(1)的解法么?
思路:快慢指针解决
判断链表是否有环应该是老生常谈的一个话题了,最简单的一种方式就是快慢指针,慢指针针每次走一步,快指针每次走两步,如果相遇就说明有环,如果有一个为空说明没有环。代码比较简单
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public boolean hasCycle(ListNode head) {
if(head == null)
return false;
ListNode slow = head;
ListNode fast = head;
if(slow != null && fast != null){
slow = head.next;
fast = head.next.next;
if(slow == fast){
return true;
}
}
return false;
}
}
2反转字符串
写出一个程序,接受一个字符串,然后输出该字符串反转后的字符串。(字符串长度不超过1000)
示例1
输入:“abcd”
返回值:“dcba”
思路:/字符串拼接法:将后面的字符放在最前面
import java.util.*;
public class Solution {
/**
* 反转字符串
* @param str string字符串
* @return string字符串
*/
public String solve (String str) {
// write code here
String word = "";
for(int i = 0; i<=str.length()-1; i++){
word = str.charAt(i) +word; //拼接字符串
}
return word;
}
}
注:charAt() 方法用于返回指定索引处的字符。索引范围为从 0 到 length() - 1。为String类的一个方法
3合并两个有序数组
给出两个有序的整数数组 A和B ,请将数组 B合并到数组 A中,变成一个有序的数组A
注意:可以假设 A数组有足够的空间存放 B数组的元素, A和B 中初始的元素数目分别为m 和 n
思路:从后往前看,在每一个位置上选择A和B中较小的那一个
public class Solution {
public void merge(int A[], int m, int B[], int n) {
int a = m-1;
int b = n-1;
for(int i = m+n-1 ; i >= 0 ; i--)//需要填m+n次
{
if(b<0||(a>=0&&A[a]>=B[b]))
//B数组中的数全部用完了就填A数组中的数 a数组中的数没有用完,并且A数组的数大
{
A[i]=A[a];
a--;
}
else
{
A[i]=B[b];
b--;
}
}
}
}
一次编辑
字符串有三种编辑操作:插入一个字符、删除一个字符或者替换一个字符。 给定两个字符串,编写一个函数判定它们是否只需要一次(或者零次)编辑。
解题思路
双指针:i 和 j 指针开始时均指向两个字符串的开头。
特殊判断:因为只有一次编辑机会,若两个字符串长度相差大于 1,则直接返回 false;若两个字符串相等,则直接返回 true 即可。
分别从头开始遍历两个字符串,若当前遍历的两个字符相等,即 first.charAt(i) == second.charAt(j),则直接跳过本次循环,i 和 j 指针分别后移继续比较下一个字符。
若当前遍历的两个字符不等,则不匹配的次数 + 1,即 count++:
若 count > 1,则说明这两个字符串不能通过一次编辑(或零次编辑)使它们相等,直接返回 false。
若 count <= 1,说明两个字符串还有一次编辑的机会,则将短的字符串的指针往前移一步(因为是要对长字符串进行编辑来得到短字符串,所以需要编辑时,应跳过的字符是长字符串中的字符),然后继续匹配。相当于是跳过了长字符串中的那个不相等的字符,然后短字符串的指针回退到不相等字符位置的前一个位置,然后继续遍历比较,但机会只有一次。
示例:first = “pale”,second = “ple”
i = 0,j = 0,p == p,continue;
i = 1,j = 1,a != l,此时将短字符串的指针前移一位 j−−(相当于长字符串把 ’ a ’ 直接跳过去了,即进行了一次编辑),j = 0;
i = 2,j = 1,l == l,continue;
i = 3,j = 2,e == e,结束返回 true。
class Solution {
public boolean oneEditAway(String first, String second) {
int f = first.length();
int s = second.length();
if (Math.abs(f - s) > 1) return false;
if (first.equals(second)) return true;
int count = 0; // 记录不匹配的次数。
int i = 0, j = 0; // 用来指向两字符串的指针
while (i < f && j < s) {
// 两个字符串从前往后开始遍历,如果当前两字符串字符相同就继续比较下一个。
if (first.charAt(i++) == second.charAt(j++)) {
continue;
}
count++;
if (count > 1) return false;
if (f != s) { // 若不相等,则将短字符串指针前移一位
if (f > s) j--;
else i--;
}
}
return true;
}
}
4、判断二叉树是否对称
给定一棵二叉树,判断其是否是自身的镜像(即:是否对称)
例如:下面这棵二叉树是对称的
1
/
2 2
/ \ /
3 4 4 3
下面这棵二叉树不对称。
1
/
2 2
\
3 3
备注:
希望你可以用递归和迭代两种方法解决这个问题
示例1 输入:{1,2,2} 返回值:true
示例2 输入:{1,2,3,3,#,2,#} 返回值:false
解题思路:递归,判断左右子树
import java.util.*;
/*
* public class TreeNode {
* int val = 0;
* TreeNode left = null;
* TreeNode right = null;
* }
*/
public class Solution {
/**
*
* @param root TreeNode类
* @return bool布尔型
*/
public boolean isSymmetric (TreeNode root) {
// write code here
if(root == null){
return true;
}
return dfs(root.left, root.right);
}
public boolean dfs(TreeNode left, TreeNode right){
if(left == null && right == null) return true;
if((left == null && right != null) || (left != null && right == null)){
return false;
}
if(left.val != right.val) return false;
return (dfs(left.left, right.right)) && (dfs(left.right, right.left));
}
}
5、翻转二叉树
示例:
输入:
4
/
2 7
/ \ /
1 3 6 9
输出:
4
/
7 2
/ \ /
9 6 3 1
递归思路步骤如下:
翻转根节点的左子树(递归调用当前函数)
翻转根节点的右子树(递归调用当前函数)
交换根节点的左子节点与右子节点
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode invertTree (TreeNode root) {
if (root == null) return null;
invertTree(root.left);//翻转根结点的左子树
invertTree(root.right);//翻转根结点的右子树
TreeNode tmp = root.left; //交换左子节点和右子节点
root.left = root.right;
root.right = tmp;
return root;
}
}
6、查找数组中第k大的数
问题: 查找出一给定数组中第k大的数。例如[3,2,7,1,8,9,6,5,4],第1大的数是9,第2大的数是8……
思路:
- 直接从大到小排序,排好序后,第k大的数就是arr[k-1]。
- 只需找到第k大的数,不必把所有的数排好序。这里我们借鉴了快速排序的思想,首先任取一个数字,将小于它的放到左边,大于它的放到右边,然后这个数字的位置就可以确定。通过比较k和这个数字的位置,我们就可以判断应该在这个数字的左边还是右边,然后就可以重复上面的操作。最终复杂度是O(n),但是最终数组的位置会改变