1.java 稀疏算法
eg:五子棋
思想:将棋盘定义为横列两个数组intB[],intA[],里面保存的是棋盘的初始化
然后将棋盘落子记录下来存储在二位数组int[][],并且赋值 1/2代表黑子/白字
2.数组 求在该数组当中的第二大数字
思想:定义两个int 来代表max.max2. 循环数组 ,max 和 array[i] 做比较,遇到比自己大的,将值赋予max2,然后max此时等于array[i],并在此时比较array[i] 和 max2值大小
代码逻辑:
int max,max2;
if (array.length < 2 ){
return array[0];
}
max = max2 = 0; /* 未考虑负数,如果考虑,那么max,max2的初始值为 2.-31次 */
for (int value : array) {
if (value > max) {
max2 = max;
max = value;
}
if (value < max && value > max2) {
max2 = value;
}
}
return max2;
3.给定一个数字,从数组中找两个数字相加等于目标和,输出这两个数字
方法1:暴力for循环
rivate static int sumA(int[] array,int sum){
int a,b;
for (int i = 0; i <array.length;i++){
a = array[i];
for (int j = i+1; j < array.length; j++){
b = array[j];
if (a + b == sum){
System.out.println(a);
System.out.println(b);
}
}
}
return sum;
}
方法2:使用hash,并且只需要判断此时是否containsKey(sum-array[i]) 并且此时的value 和 i 不一致,一致说明是只有一个数
private static int[] sumB(int[] array, int sum) {
Map<Integer, Integer> map = new HashMap<>();
//将所有数组转为map.key为值,value为下标
for (int i : array) {
map.put(array[i], i);
}
for (int i = 0; i < array.length; i++) {
int sub = sum - array[i];
if (map.containsKey(sub) && map.get(sub) != i) {
return new int[]{i, map.get(sub)};
}
}
return null;
}
4: 两个链表表示的数相加,这样就可以实现两个很⼤的数相加了,⽆需考虑数值 int ,float ,long的限制
思路:由个位进行运算 ,循环列表,直至 两个列表都为null时计算完毕,carry表示进位(最大也为1,因为 99 +99 < 200)
代码:/**
- 两个链表表示的数相加,这样就可以实现两个很⼤的数相加了,⽆需考虑数值 int ,float 的限制
` */
public class listSum {
/**
* eg Input:(2->4->3) + (1->4->7)
* output 3->9->0
* 243 + 147 = 390
* 思想 由个位进行运算 ,循环列表,直至 两个列表都为null时计算完毕
* 方法2:for循环两个链表
*/
static class listArray {
int val;
listArray next;
listArray(int x) {
val = x;
}
public static listArray twoNumberAdd(listArray a, listArray b) {
//初始化节点头
listArray dummyHead = new listArray(0);
//链表a的头p->个位数字
listArray p = a;
//链表b的头p->个位数字
listArray q = b;
//从节点第一位开始运算 也就是个位数
listArray curr = dummyHead;
//进位,默认是0 不进位
int carry = 0;
while (p != null || q != null){
int x = (p != null) ? p.val : 0;
int y = (q != null) ? q.val : 0;
//判断是否要进位
int sum = carry + x + y;
//进位永远是1
carry = sum / 10;
//节点头移动判断
curr.next = new listArray(sum % 10);
//节点头更新
curr = curr.next;
if (p != null) {
//下一位运算,替换值
p = p.next;
}
if (q != null) {
//下一位运算,替换值
q = q.next;
}
}
if (carry > 0){
//更新链表
curr.next = new listArray(carry);
}
return dummyHead.next;
}`
5.给定⼀个字符串,找到没有重复字符的最⻓⼦串,返回它的⻓度
思路:简单粗暴 两个循环 加一个 条件判断
/**
* 给定⼀个字符串,找到没有重复字符的最⻓⼦串,返回它的⻓度
*/
public class findLongString {
/**
* 思路1:简单粗暴 两个循环穷举所有⼦串,然后再⽤⼀个函数判断该⼦串中有没有重复的字符
* set 天然不重复
*/
private static int lengthOfSubstring(String s){
int suffice = 0;
for (int i = 0; i < s.length();i++){
for (int j = i + 1; j <= s.length(); j++){
if (repeat(s,i,j)){
suffice = Math.max(suffice, j - i);
}
}
}
System.out.println(suffice);
return 0;
}
private static boolean repeat(String s, int start, int end){
Set<Character> set = new HashSet<>();
for(int i = start; i < end; i++){
Character charAt = s.charAt(i);
if (set.contains(charAt)){
return false;
}
set.add(charAt);
}
return true;
}
public static void main(String[] args) {
String a = "asnfuanfdinfgapndsomdaihggrngaosdjsopmopdgjsd";
lengthOfSubstring(a);
}
}
方法二:滑动窗口算法可以优化掉很多不需要再判断的字符串
* 优化思想: 比如 string[0,8) 之前没有重复,按照思路1 接下来就要判断 string[0,9)有没有重复,而此时又多了一次string[0,8)无效循环
* 那我 我们只需要判断string[9] 是否在string[0,8)中即可,不在的话,就表明 str[0,9) 中没有重复的字符。 如果在的后,那么后续的string[0,xx)也不用再判断了,
* 那么从String[1,xx)在开始判断
private static int method2(String s){
Set<Character> set = new HashSet<>();
int suffice = 0;
int i = 0;
int j = 0;
while (i < s.length() && j < s.length()){
if (!set.contains(s.charAt(j))){
set.add(s.charAt(j++));
suffice = Math.max(suffice , j - i);
}else {
set.remove(s.charAt(i++));
}
}
return suffice;
}
方法三:
/**
* 思路3 将set 转用 map存储,此时可以直接不考虑之前不满足的情况,而无需 在让i++ ,j++ 正在进行循环判断
*/
private static int method3(String s){
//k-> 字符串 v-> 下标
Map<Character, Integer> map = new HashMap<>();
int suffice = 0;
for (int j = 0, i = 0; j < s.length(); j++){
//判断map是否包含后一位的下标value ->不包含的话,map 继续 put(k,v) 包含的话,对map的 key 进行 value 替换,并且对i 进行 跳跃到j的后一位,j之前100%是重复,所以直接不考虑
if (map.containsKey(s.charAt(j))){
i = Math.max(map.get(s.charAt(j)), i);
}
suffice = Math.max(suffice, j - i +1);
// j + 1 代表 stirng 下标 i 移动的位置 即 i 跳跃 直接不考虑 j 前方的所有字符串
map.put(s.charAt(j),j + 1);
}
return suffice;
}
6:已知两个有序数组,找到两个数组合并后的中位数
/**
* 方法一:两个数组合并为一个新的数组并且在排序,在求中位数
*/
private static long findMiddleNumber(int[] A, int[] B){
int[] nums = new int[A.length + B.length];
for (int i = 0; i < nums.length; i++){
if (i < A.length){
nums[i] = A[i];
} else {
nums[i] = B[i - A.length];
}
}
//新数组排序
Arrays.sort(nums);
// 偶数
if (nums.length % 2 == 0){
return (nums[nums.length / 2 -1] + nums[nums.length / 2]) / 2;
}else{
//奇数
return nums[(nums.length + 1) /2];
}
}
7:回文字符串 : 回文字符串并输出最长的回文字符串/或者长度
/**
* 方法一: 从中折叠, 循环判断 从中折叠 前一位 和 后一位 是否 相等
*/
private static boolean isPalindrome(String words) {
for (int i = 0; i < words.length() / 2; i++) {
if (words.charAt(i) != words.charAt(words.length() - i - 1)) {
return false;
}
}
return true;
}
private static String findBestLongWords(String words) {
int w = words.length();
int maxLong = 0;
//需要一个初始化字符串来记录回文字符串
String s = "";
for (int i = 0; i < w; i++) {
for (int j = i + 1; j <= w; j++) {
String pd = words.substring(i,j);
if (isPalindrome(pd) && pd.length() > maxLong){
maxLong = Math.max(maxLong, pd.length());
s = pd;
}
}
}
return s;
}
8:给定一个字符串,按照竖着的Z方式排列字符
/**
* 按照写Z的过程 正常循环写,然后便利到两端的话就改变方向
* numRows 为input s为input
*/
private static String Z(String s, int numRows) {
if (numRows == 1) {
return s;
}
//rows 指需要build的行数
List<StringBuilder> rows = new ArrayList<>();
//避免最后出现越界->取较小值
for (int i = 0; i < Math.min(numRows, s.length()); i++) {
rows.add(new StringBuilder());
}
int curRow = 0;
//代表当前方向
boolean goingDown = false;
for (char c : s.toCharArray()) {
//行数拼接字符串
rows.get(curRow).append(c);
//转向
if (curRow == 0 || curRow == numRows - 1) {
goingDown = !goingDown;
}
//控制方向 1 向下 -1 向上
curRow += goingDown ? 1 : -1;
}
StringBuilder builder = new StringBuilder();
for (StringBuilder row : rows) {
builder.append(row);
}
System.out.println(builder.toString());
return builder.toString();
}
public static void main(String[] args) {
String s = "sdertfdvsads";
Z(s,5);
zTwo(s,5);
}
/**
* 思路二 查找规律 周期性为 2 * numRows -2 ,然后在开启重复相同路径
* 第一行的规律就是 下标 0
* 第二行的规律就是 下标1 第二个下标就是下一个周期的0下标 - 当前下标 eg 第二行 下标1,下标(2 * numRows -2 ) - 1
* 第三行的规律就是 下标2 第二个下标就是下一个周期的0下标 - 当前下标 eg 第二行 下标1,下标(2 * numRows -2 ) - 2
* 一次类推 ,而且 2 * numRows -2 。length 为一个周期,下个周期循环 之前的规律,只需要在 下个规律的周期下标 + 2 * numRows -2即可
*/
private static String zTwo(String s, int numRows){
if (numRows == 1){
return s;
}
StringBuilder builder = new StringBuilder();
int size = s.length();
int guilv = 2 * numRows - 2;
//i 代表 第几行 从第一行下标0开始计算,第一行全部完毕 第二行
for (int i = 0; i < numRows; i++){
//每次增加一个周期
for (int j = 0; j + i < size; j += guilv){
builder.append(s.charAt( j + i));
//不等于0行和最后一行
if (i != 0 && i != numRows -1 && j + guilv - i < size){
builder.append(s.charAt(j + guilv - i));
}
}
}
return builder.toString();
}
9:输入它的整数,输出它的倒置
eg i:123 o:321 ; -123 -321 250 52
private static int invert(int num){
long result = 0;
while (num != 0){
//取余
int top = num % 10;
//每次缩小10倍
num = num / 10;
//倒置为第一位
result = result * 10 + top;
}
//判断是否溢出
if ( result > Integer.MAX_VALUE || result < Integer.MIN_VALUE){
return 0;
}
System.out.println((int) result);
return (int) result;
}
public static void main(String[] args) {
int a = 1215487;
invert(a);
}
10:判断是不是回文数,负数不是回文数
eg 121 tue -121 false 10 false 101 ture
/**
* 思路一
* int 转 string 然后判断 是不是回文串
*/
private boolean huiwen(int num){
//首先判断int 是否 为负数 超过范围 自动false
if (num < 0){
return false;
}
String number = String.valueOf(num);
for (int i = 0; i < number.length() / 2; i++) {
if (number.charAt(i) != number.charAt(number.length() - i - 1)) {
return false;
}
}
return true;
}
/**
* 思路二
* 假设存在这么⼀个数,倒置后是超出 int 范围的,并且它是回⽂数字
* int 最⼤为 2147483647
* 有没有可能是最⾼位⼤于 2 导致的溢出,⽐如最⾼位是 3 ,因为是回⽂串,所以最低位是 3 ,这就将导致
* 转置前最⾼位也会是 3 ,所以不可能是这种情况
* 有没有可能是第 2 ⾼位⼤于 1 导致的溢出,此时保持最⾼位不变,假如第 2 ⾼位是 2,因为是回⽂串,所
* 以个位是 2,⼗位是 2 ,同样的会导致倒置前超出了 int 的最⼤值,所以也不可能是这种情况
* 同理,第 3 ⾼位,第 4,第 5,直线左边的都是上述的情况,所以不可能是前边的位数过⼤
* 为了保证这个数是溢出的,前边 5 位必须固定不变了,因为它是回⽂串,所以直线后的灰⾊数字就⼀定是 4
* ⽽此时不管后边的数字取多少,都不可能是溢出的了
*/
private boolean huiwenTwo(int num){
if (num < 0){
return false;
}
long result = 0;
//倒置num
while (num != 0){
//取余
int top = num % 10;
//每次缩小10倍
num = num / 10;
//倒置为第一位
result = result * 10 + top;
}
//判断 num 与 倒置 是否一致
return num == result;
}