字节算法

1.输入字符串检查括号是否匹配

import java.util.Stack;
public class Main{
	public static viod main(String[] args) {
	Scanner sc = new Scanner(System.in);
	while(sc.hasNext()) {
	String s = sc.next();
	System.out.println(Match(s));
} 
}
	private static boolean Match(String s){
	Stack<Character> stack = new Stack<>();
	boolean flag = true;
        char[] temp = s.toCharArray();
        for(char ch : temp){
	if(ch == '(' || ch == '{' || ch == '['){
	stack.push(ch);
	}else{
	if(!stack.isEmpty()) {
	Character c = stack.peep();
        if(isMatch(c,ch)){
	stack.pop();
	}else{
	flag = false;
	break;
	}
	}else{
	flag = false;
	break;
	}
	}
}
        }
        if(stack.size() != 0){
	flag = false;
	break;
	}
	private static boolean isMatch(char c ,char ch){
	if(ch == '(' && c == ')'){
}	return true;
        if(ch == '{' && c == '}'){
	return true;
	}
        if(ch == '[' && c == ']'){
	return true;
	}
	return false;
}

2.单例:
懒汉式:在这里插入图片描述
2.饿汉式
在这里插入图片描述
3.双检锁
在这里插入图片描述
4.静态内部类
在这里插入图片描述
5.无序数组中最长的递增子序列

class Solution {
    public int findLengthOfLCIS(int[] nums) {
        int ans = 0, anchor = 0;
        for (int i = 0; i < nums.length; ++i) {
            if (i > 0 && nums[i-1] >= nums[i]) anchor = i;
            ans = Math.max(ans, i - anchor + 1);
        }
        return ans;
    }

6.判断字符是否是回文串
思路其实是从中间外一直延伸,当左右两个边界相等的时候,就进行记录当前的字符串的长度。

class Solution {
    public String longestPalindrome(String s) {
       if(s.length() == 0)return s;
        int max = 1;
        int left = 0;//记录字符串左边
        int right = 0;//记录字符串右边
        for(int i = 0;i < s.length();i ++) {
            int l = i - 1;//奇数情况
            int r = i + 1;
            while(l >= 0 && r < s.length() && s.charAt(l) == s.charAt(r) ) {
                int len = (r - l + 1);
                if(len > max) {
                    max = len;
                    left = l;
                    right = r;
                }
                l --;
                r ++;
            }
            //偶数情况
            l = i;
            r = i + 1;
            while(l >= 0 && r < s.length() && s.charAt(l) == s.charAt(r) ) {
                int len = (r - l + 1);
                if(len > max) {
                    max = len;
                    left = l;
                    right = r;
                }
                l --;
                r ++;
            }
            
        }
        return s.substring(left,right + 1);
    }
}

7.无重复子串
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。

class Solution {
    public int lengthOfLongestSubstring(String s) {
        Map<Character,Integer> map = new HashMap<>();
        int ans = 0;
        for(int i = 0,j = 0;j < s.length(); j ++){
            if(map.containsKey(s.charAt(j))){
                i = Math.max(map.get(s.charAt(j)),i);
            }
            ans = Math.max(ans,j - i + 1);
            map.put(s.charAt(j),j + 1);
        }
        return ans;
    }
}

8.一个二维字符矩阵
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一格开始,每一步可以在矩阵中向左、右、上、下移动一格。如果一条路径经过了矩阵的某一格,那么该路径不能再次进入该格子。例如,在下面的3×4的矩阵中包含一条字符串“bfce”的路径(路径中的字母用加粗标出)。
[[“a”,“b”,“c”,“e”],
[“s”,“f”,“c”,“s”],
[“a”,“d”,“e”,“e”]]
但矩阵中不包含字符串“abfb”的路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入这个格子。
思路:使用深度优先遍历算法,把二维数组,字符串数组,下表,k是字符数组下标,而i,j是二维数组下标。
标记当前矩阵元素: 将 board[i][j] 值暂存于变量 tmp ,并修改为字符 ‘/’ ,代表此元素已访问过,防止之后搜索时重复访问。
搜索下一单元格: 朝当前元素的 上、下、左、右 四个方向开启下层递归,使用 或 连接 (代表只需一条可行路径) ,并记录结果至 res 。
还原当前矩阵元素: 将 tmp 暂存值还原至 board[i][j] 元素。

class Solution {
    public boolean exist(char[][] board, String word) {
        char[] words = word.toCharArray();
        for(int i = 0; i < board.length; i++) {
            for(int j = 0; j < board[0].length; j++) {
                if(dfs(board, words, i, j, 0)) return true;
            }
        }
        return false;
    }
    boolean dfs(char[][] board, char[] word, int i, int j, int k) {
        if(i >= board.length || i < 0 || j >= board[0].length || j < 0 || board[i][j] != word[k]) return false;
        if(k == word.length - 1) return true;
        char tmp = board[i][j];
        board[i][j] = '/';
        boolean res = dfs(board, word, i + 1, j, k + 1) || dfs(board, word, i - 1, j, k + 1) || 
                      dfs(board, word, i, j + 1, k + 1) || dfs(board, word, i , j - 1, k + 1);
        board[i][j] = tmp;
        return res;
    }
}

M,N 分别为矩阵行列大小, KK 为字符串 word 长度。
时间复杂度:
设字符串长度为 KK ,搜索中每个字符有上、下、左、右四个方向可以选择,舍弃回头(上个字符)的方向,剩下 33 种选择,因此方案数的复杂度为 O(3^K)
空间复杂度:O(K)
9.驼峰字符串
(1)将驼峰命名转为小写下划线命名

public static String underscoreName(String camelCaseName) {
    StringBuilder result = new StringBuilder();
    if (camelCaseName != null && camelCaseName.length() > 0) {
        result.append(camelCaseName.substring(0, 1).toLowerCase());
        for (int i = 1; i < camelCaseName.length(); i++) {
            char ch = camelCaseName.charAt(i);
            if (Character.isUpperCase(ch)) {
                result.append("_");
                result.append(Character.toLowerCase(ch));
            } else {
                result.append(ch);
            }
        }
    }
    return result.toString();
}

下划线转驼峰 user_name

public static String camelCaseName(String underscoreName) {
    StringBuilder result = new StringBuilder();
    if (underscoreName != null && underscoreName.length() > 0) {
        boolean flag = false;
        for (int i = 0; i < underscoreName.length(); i++) {
            char ch = underscoreName.charAt(i);
            if ("_".charAt(0) == ch) {
                flag = true;
            } else {
                if (flag) {
                    result.append(Character.toUpperCase(ch));
                    flag = false;
                } else {
                    result.append(ch);
                }
            }
        }
    }
    return result.toString();
}

(2)驼峰字符串匹配
时间复杂度:O(M+N*K)
设quriesquries数组长度为N,字符串总长度为M,pattrenpattren的长度为K
空间复杂度:O(1)O(1) 不包含返回值数组所占用空间
思路:
开始分别用两个指针idx1和idx2指向query和pattrn的头部。
判断两个指针所指向的字符是否相等,如果相等则同时后移
若不相等,则idx1的指针不断后移,直到走到query字符串末尾或和idx2指向的字符相等。注意根据题意我们只能插入小写字母,故idx1后移的过程中若遇到不匹配大写字母,则立即返回false。
当指针idx1或idx2走到字符串的末尾时退出循环,这时我们要判断idx2是否走到了pattrn字符串的末尾,如果不是,说明我们还有剩余字符未成功匹配,返回false。同时我也要判断query中剩余的字符中是否全是小写字母,若不是返回false。

class Solution {
    public List<Boolean> camelMatch(String[] queries, String pattern) {
        List<Boolean> ans = new ArrayList<>();
        for (String query : queries) 
            ans.add(isMatch(query, pattern));
        return ans;
        
    }
    private boolean isMatch(String query, String pattern) {
        int idx1 = 0, idx2 = 0, n1 = query.length(), n2 = pattern.length();
        while (idx1 < n1 && idx2 < n2){
            char ch1 = query.charAt(idx1), ch2 = pattern.charAt(idx2);
            if (ch1 == ch2) {
                idx1++;idx2++;
            } else {
                if (ch1 >= 'A' && ch1 <= 'Z') return false;
                idx1++;
            }
        }
        if (idx2 != n2) return false;
        while (idx1 < n1) {
            char ch1 = query.charAt(idx1++);
            if (ch1 >= 'A' && ch1 <= 'Z') return false;
        }
        return true;
    }
}

10.找出数组中出现次数长度超过一半的那个数

class Solution {
    public int majorityElement(int[] nums) {
    ArrayList<Integer> list = new ArrayList<>();
        int count = 0;
        int len = nums.length;
        int i;
        Arrays.sort(nums);
        for ( i = 0; i < nums.length - 1; i++) {
            if (!list.contains(nums[i])) 
                list.add(nums[i]);
            count ++;
            if (nums[i] != nums[i + 1]) {
                if (count > len / 2) {
                   break;
                } else {
                    list.clear();
                }
            }
        }
        return nums[i];
    }
    }

解题思路:
1.哈希表统计法: 遍历数组 nums ,用 HashMap 统计各数字的数量,最终超过数组长度一半的数字则为众数。此方法时间和空间复杂度均为 O(N)。
2.数组排序法: 将数组 nums 排序,由于众数的数量超过数组长度一半,因此 数组中点的元素 一定为众数。此方法时间复杂度 O(N log_2 N)。
3.摩尔投票法: 核心理念为 “正负抵消” ;时间和空间复杂度分别为 O(N) 和 O(1) ;是本题的最佳解法。
假设第一个数字是众数,把第一过数字赋值给x,如果现在这个数与默认众数相等,则votes进行++,否则votes进行–。

class Solution {
    public int majorityElement(int[] nums) {
        int x = 0, votes = 0;
        for(int num : nums){
            if(votes == 0) x = num;
            votes += num == x ? 1 : -1;
        }
        // 验证 x 是否为众数
        for(int num : nums)
            if(num == x) count++;
        return count > nums.length / 2 ? x : 0; // 当无众数时返回 0
    }
        return x;
    }
}

11.删除数组重复元素
给定一个排序数组,你需要在 原地 删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。
不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。

public int removeDuplicates(int[] nums) {
    if (nums.length == 0) return 0;
    int i = 0;
    for (int j = 1; j < nums.length; j++) {
        if (nums[j] != nums[i]) {
            i++;
            nums[i] = nums[j];
        }
    }
    return i + 1;
}

12.两个栈实现一个队列
思路:先将数据存到第一个栈里,再将第一个栈里的元素全部出栈到第二个栈,第二个栈出栈,即可达到先进先出。

import java.util.Stack;
public class TwoStacksQueue {
    public Stack<Integer> stackPush;
    public Stack<Integer> stackPop;

    public TwoStacksQueue() {
        stackPush = new Stack<Integer>();
        stackPop = new Stack<Integer>();
    }

    //元素进栈
    public void add(int pushInt) {
        stackPush.push(pushInt);
    }

    public int poll() {
        if (stackPop.empty() && stackPush.empty()) {
            throw new RuntimeException("Queue is empty!");
        } else if (stackPop.empty()) {
            while (!stackPush.empty()) {
                stackPop.push(stackPush.pop());
            }
        }
        return stackPop.pop();
    }
//和poll效果一样
//    public int peek() {
//        if (stackPop.empty() && stackPush.empty()) {
//            throw new RuntimeException("Queue is empty!");
//        } else if (stackPop.empty()) {
//            while (!stackPush.empty()) {
//                stackPop.push(stackPush.pop());
//            }
//        }
//        return stackPop.peek();
//    }

    public static void main(String[] args) {

        TwoStacksQueue queue = new TwoStacksQueue();
        queue.add(2);
        queue.add(4);
        queue.add(7);
        queue.add(13);
        System.out.println(queue.poll());
        System.out.println(queue.poll());
    }
}

13.两个队列实现一个栈
数据的插入原则:保持一个队列为空,一个队列不为空,往不为空的队列中插入元素

import java.util.LinkedList;
import java.util.Queue;
/**
 * 两个队列实现一个栈
 *  
 * 一个队列加入元素,弹出元素时,需要把队列中的 元素放到另外一个队列中,删除最后一个元素
 * 两个队列始终保持只有一个队列是有数据的
 *
 */
public class StackByQueue<T> {
 
	private Queue<T> queue1 = new LinkedList<>();
	
	private Queue<T> queue2 = new LinkedList<>();
	
	/**
  	 * 压栈 
  	 * 
  	 * 入栈非空的队列
	 */
	public boolean push(T t) {
		if (!queue1.isEmpty()) {
			return queue1.offer(t);//插入数据
		} else {
			return queue2.offer(t);
		}
	}
	
	/**
	 * 弹出并删除元素 
	 */
	public T pop() {
		if (queue1.isEmpty() && queue2.isEmpty()) {
			throw new RuntimeException("queue is empty");
		}
		if (!queue1.isEmpty() && queue2.isEmpty()) {
			while (queue1.size() > 1) {
				queue2.offer(queue1.poll());
			}
			return queue1.poll();//先入的后出
		}
		if (queue1.isEmpty() && !queue2.isEmpty()) {
			while (queue2.size() > 1) {
				queue1.offer(queue2.poll());
			}
			return queue2.poll();
		}
		
		return null;
	}
	
	@Override
	public String toString() {
		return this.queue1.toString() + ", " +this.queue2.toString();
	}
	
	public static void main(String[] args) {
		StackByQueue<Integer> s = new StackByQueue<>();
		s.push(1);
		s.push(2);
		s.push(3);
		s.pop();
		System.out.println(s);
		s.push(4);
		s.push(5);
		s.pop();
		System.out.println(s);
	}
}

14.输出一个集合的所有子集合
找出一个集合的所有子集合,用排列组合的方式来解答此问题的话,假设集合里面有n个元素,那个子集合的数目为2^n.
具体思路为:对于集合里面的任何一个元素,有两种可能,一种是在子集合里,另一种是不在子集合里。假如我们已经得到n-1个元素的子集合,那么n个元素的子集合是:n-1个元素的子集合 + n-1个元素的子集合中的所有集合都添加进额外的那个元素。

static ArrayList<ArrayList<Integer>> getSubsets(ArrayList<Integer> set, int index){
		ArrayList<ArrayList<Integer>> allsubsets;
		if(set.size() == index){ 
			allsubsets = new ArrayList<ArrayList<Integer>>();
			allsubsets.add(new ArrayList<Integer>()); //empty set
		}else{
			allsubsets = getSubsets(set, index+1);
			int item = set.get(index);
			ArrayList<ArrayList<Integer>> moresubsets =  new ArrayList<ArrayList<Integer>>();
			for(ArrayList<Integer> s: allsubsets){
				ArrayList<Integer> newSubset = new ArrayList<Integer>();
				newSubset.addAll(s);
				newSubset.add(item);
				moresubsets.add(newSubset);
			}
			allsubsets.addAll(moresubsets);
		}
		return allsubsets;
	}
public static void main(String[] args){
		ArrayList<Integer> s = new ArrayList<Integer>();
		s.add(1);
		s.add(2);
		s.add(3);
		ArrayList<ArrayList<Integer>> allsubsets = getSubsets(s, 0);
		for(ArrayList<Integer> set : allsubsets){
			System.out.println(set);
		}

15.扑克牌中的顺子
从扑克牌中随机抽5张牌,判断是不是一个顺子,即这5张牌是不是连续的。2~10为数字本身,A为1,J为11,Q为12,K为13,而大、小王为 0 ,可以看成任意数字。A 不能视为 14。
简单来说就是要是5个数字,最大和最小差值在5以内,并且没有重复数值。用一个set来填充数据,0不要放进去。set的大小加上0的个数必须为5个。此外set中数值差值在5以内。

import java.util.TreeSet;
public class Solution {
    public boolean isContinuous(int [] n) {
        if (n.length < 5 || n.length > 5) {
            return false;
        }
        int num = 0;
        TreeSet<Integer> set = new TreeSet<> ();
        for (int i=0; i<n.length;i++) {
            if (n[i]==0) {
                num ++;
            } else {
                set.add(n[i]);
            }
        }
        if ((num + set.size()) != 5) {
            return false;
        }
        if ((set.last() - set.first()) < 5) {
            return true;
        }
        return false;
    }
}

16.链表逆序:
在这里插入图片描述
17.输出比给定数大的下一个数字
可以使用字典排序
第一步先找到num[i +1] < num[i]
第二步确定反转的起点i,并且又从后开始往前遍历,找到,nums[j] < nums[i]
第三步就是把第一步与第二步确定位置的数字进行反转

public class Solution {
    public void nextPermutation(int[] nums) {
        int i = nums.length - 2;
        while (i >= 0 && nums[i + 1] <= nums[i]) {
            i--;
        }
        if (i >= 0) {
            int j = nums.length - 1;
            while (j >= 0 && nums[j] <= nums[i]) {
                j--;
            }
            swap(nums, i, j);
        }
        reverse(nums, i + 1);
    }

    private void reverse(int[] nums, int start) {
        int i = start, j = nums.length - 1;
        while (i < j) {
            swap(nums, i, j);
            i++;
            j--;
        }
    }

    private void swap(int[] nums, int i, int j) {
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }
}

18.两个长字符串数字求和
思路:我们直接计算是不行的,需要每一位字符一个一个相加,相加之后在一位一位添加到一个新字符串中,但是如果说两个大于5的数值相加,就会溢出一位,相应的上一位就应该加1,所以说我们需要将两个字符串反转,从小到大一个一个的加,溢出之后,在进位上加1。

StringBuffer s1 = new StringBuffer(str1).reverse();
        StringBuffer s2 = new StringBuffer(str2).reverse();
        StringBuffer res = new StringBuffer();

        int len1 = s1.length();
        int len2 = s2.length();
        int len;

        if (len1 < len2) {
            len = len2;
            int count = len2 - len1;
            while (count-- > 0)
                s1.append('0');
        } else {
            len = len1;
            int count = len1 - len2;
            while (count-- > 0)
                s2.append('0');
        }

        int overflow = 0; 
        int num;

        for (int i = 0; i < len; i++) {
            num = s1.charAt(i) - '0' + s2.charAt(i) - '0' + overflow;
            if (num >= 10) {
                overflow = 1;
                num -= 10;
            } else {
                overflow = 0;
            }
            res.append(String.valueOf(num));
        }

        if (overflow == 1)
            res.append(1);

        return res.reverse().toString();

19.求两个正整数的最小公倍数

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值