风-fmgao

导航

简单算法2

二分查找

package com.sly.uploadfile.algorithm.pack1;

import java.util.Arrays;

/**
 * Created by fmgao on 2019/9/25.
 * <p>
 * Java语言二分查找代码实现
 */
public class ErFenChaZhao {

    /**
     * 二分查找key值对应的下标
     *
     * @param source 输入的源数组 ,请保证为一个有序数组
     * @param key    需要查找的值
     * @return 正数为查找到的坐标,-1表示没有查到
     */
    public static int binarySearch(int[] source, int key) {
        int low = 0;
        int high = source.length - 1;
        while (low <= high) {
            int mid = (low + high) >>> 1; //使用位移运算法高效地获取折中下标,这里不考虑符号,所以使用>>>
            int midVal = source[mid];
            if (midVal < key) {
                low = mid + 1;
            } else if (midVal > key) {
                high = mid - 1;
            } else
                return mid;
        }
        return -1;
    }

    public static void main(String[] args) {
        int[] source = new int[]{12, 213, 232, 343, 123, -1, 123, 232424, 1253, 56, 456, 234, -2342};
        //保证数组为有序数组
        Arrays.sort(source);
        //打印排序后的数组元素
        System.out.print("Sorted Source : ");
        for (int i = 0; i < source.length; i++) {
            System.out.print(source[i] + " ");
        }
        System.out.println();
        System.out.println(binarySearch(source, 56));
    }

}

俩数相加

package com.sly.uploadfile.algorithm.twoadd;

/**
 * Created by fmgao on 2019/11/13.
 * <p>
 * 给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,
 * 并且它们的每个节点只能存储 一位 数字。
 * <p>
 * 如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。
 * <p>
 * 您可以假设除了数字 0 之外,这两个数都不会以 0 开头。
 * <p>
 * 示例:
 * <p>
 * 输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
 * 输出:7 -> 0 -> 8
 * 原因:342 + 465 = 807
 */
public class TwoAdd {

    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        ListNode dumpHead = new ListNode(0);
        ListNode p = l1, q = l2, curr = dumpHead;
        int carry = 0;
        while (p != null || q != null) {
            int x = (p != null) ? p.data : 0;
            int y = (q != null) ? q.data : 0;
            int sum = x + y + carry;
            carry = sum / 10;

            curr.next = new ListNode(sum % 10);
            curr = curr.next;
            if (p != null) p = p.next;
            if (q != null) q = q.next;
        }
        if (carry != 0) {
            curr.next = new ListNode(carry);
        }
        return dumpHead.next;
    }


    public static void main(String[] args) {
        SingleLinkedList l1 = new SingleLinkedList();
        l1.addData(1);
        l1.addData(2);
        l1.addData(5);
        SingleLinkedList l2 = new SingleLinkedList();
        l2.addData(3);
        l2.addData(2);
        l2.addData(7);
        TwoAdd solution = new TwoAdd();
        ListNode l3 = solution.addTwoNumbers(l1.head, l2.head);
        while (l3 != null) {
            if (l3.next == null) {
                System.out.print(l3.data);
                l3 = l3.next;
            } else {
                System.out.print(l3.data + "->");
                l3 = l3.next;
            }
        }
        System.out.println();
        System.out.println("/:" + 25 / 10);
        System.out.println("%:" + 25 % 10);
    }
}

 

俩数相加

package com.sly.uploadfile.algorithm.twoadd;

import java.util.HashMap;
import java.util.Map;

/**
 * Created by fmgao on 2019/12/30.
 */
public class TwoNum {


    public static void main(String[] args) {
        int[] nums = {2, 7, 11, 15};
        int tar = 22;
        int[] ints = twoNum(nums, tar);
        for (int s : ints) {
            System.out.println(s);
        }
    }

    public static int[] twoNum(int[] nums, int target) {
        Map<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < nums.length; i++) {
            int com = target - nums[i];
            if (map.containsKey(com)) {
                return new int[]{map.get(com), i};
            } else {
                map.put(nums[i], i);
            }
        }
        throw new IllegalArgumentException("No two sum solution");
    }

}

是否有重复元素

package com.sly.uploadfile.algorithm;

import java.util.HashMap;
import java.util.Map;

/**
 * Created by fmgao on 2019/9/27.
 * <p>
 * [Leetcode] 220. 存在重复元素 II java
 * <p>
 * 给定一个整数数组,判断数组中是否有两个不同的索引 i 和 j,
 * 使得 nums [i] 和 nums [j] 的差的绝对值最大为 t,并且 i 和 j 之间的差的绝对值最大为 ķ。
 * <p>
 * Example 1:
 * <p>
 * Input: nums = [1,2,3,1], k = 3, t = 0
 * Output: true
 * <p>
 * Example 2:
 * <p>
 * Input: nums = [1,0,1,1], k = 1, t = 2
 * Output: true
 * <p>
 * Example 3:
 * <p>
 * Input: nums = [1,5,9,1,5,9], k = 2, t = 3
 * Output: false
 */
public class ContainsNearByDuplicate {
    public static void main(String[] args) {
        int[] nu = {1, 2, 3, 1};
        boolean b = containsNearByAlmostDuplicate(nu, 21, 1);
        System.out.println(b);
    }

    public static boolean containsNearByAlmostDuplicate(int[] a, int k, int t) {
//        if (k < 1 || t < 0 || nums == null || nums.length < 2) {
//            return false;
//        }
//        SortedSet<Long> set = new TreeSet<>();
//        for (int j = 0; j < nums.length; j++) {
//            SortedSet<Long> subset = set.subSet((long) nums[j] - t, (long) nums[j] + t + 1);
//            if (!subset.isEmpty()) {
//                return true;
//            }
//            if (j >= k) {
//                set.remove((long) nums[j - k]);
//            }
//            set.add((long) nums[j]);
//        }
//        for (Long ss : set) {
//            System.out.println(ss);
//        }

        /**
         * 给定一个整数数组和一个整数 k,判断数组中是否存在两个不同的索引 i 和 j,使得 nums [i] = nums [j],并且 i 和 j 的差的绝对值最大为 k。

         示例 1:

         输入: nums = [1,2,3,1], k = 3
         输出: true

         示例 2:

         输入: nums = [1,0,1,1], k = 1
         输出: true

         示例 3:

         输入: nums = [1,2,3,1,2,3], k = 2
         输出: false
         */

        // (双指针法,快慢指针加了一个限定(Math.abs ( i-j )<=k),相当于滑动窗口(有滑动限定))+map存储元素
        int j;
        Map<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < a.length; i++) {
            //   当map中存在数组元素时,证明两个元素相同
            if (map.containsKey(a[i])) {
                //   让j等于map中与数组元素相等的那个键对应值
                j = map.get(a[i]);
                //   判断新的这个(遍历后的)索引和Map中的索引的差是否小于k,小于则输出true。
                if (Math.abs(i - j) <= k) {
                    System.out.println("true");
                }
                //将新的索引值添加到map中
                map.put(a[i], i);
            } else {
                // 向map中添加元素
                map.put(a[i], i);
            }
        }
        System.out.println("false");
        return false;
    }

}

数字1的个数

package com.sly.uploadfile.algorithm;

/**
 * Created by fmgao on 2019/9/29.
 * <p>
 * [LeetCode] Number of Digit One 数字1的个数
 * Given an integer n, count the total number of digit 1 appearing in all non-negative integers less than or equal to n.
 * For example:
 * Given n = 13,
 * Return 6, because digit 1 occurred in the following numbers: 1, 10, 11, 12, 13.
 */

/**
 《编程之美》上这样说:

 设N = abcde ,其中abcde分别为十进制中各位上的数字。

 如果要计算百位上1出现的次数,它要受到3方面的影响:百位上的数字,百位以下(低位)的数字,百位以上(高位)的数字。

 如果百位上数字为0,百位上可能出现1的次数由更高位决定。比如:12013,
 则可以知道百位出现1的情况可能是:100~199,1100~1199,2100~2199,,...,11100~11199,一共1200个。
 可以看出是由更高位数字(12)决定,并且等于更高位数字(12)乘以 当前位数(100)。注意:高位数字不包括当前位

 如果百位上数字为1,百位上可能出现1的次数不仅受更高位影响还受低位影响。比如:12113,
 则可以知道百位受高位影响出现的情况是:100~199,1100~1199,2100~2199,,....,11100~11199,一共1200个。
 和上面情况一样,并且等于更高位数字(12)乘以 当前位数(100)。
 但同时它还受低位影响,百位出现1的情况是:12100~12113,一共14个,等于低位数字(13)+1。 注意:低位数字不包括当前数字

 如果百位上数字大于1(2~9),则百位上出现1的情况仅由更高位决定,比如12213,
 则百位出现1的情况是:100~199,1100~1199,2100~2199,...,11100~11199,12100~12199,一共有1300个,
 并且等于更高位数字+1(12+1)乘以当前位数(100)
 */
public class CountDigitOne {

    public static void main(String[] args) {
        int a = 27;
        int i = countDigitOne(a);
        System.out.println(i);
    }

    public static int countDigitOne(int n) {
        if (n < 1) {
            return 0;
        }
        int res = 0;
        long i = 1;
        while (n >= i) {
            res += (n / i + 8) / 10 * i + ((n / i) % 10 == 1 ? (n % i + 1) : 0);
            i *= 10;
        }
        return res;
    }
}

package com.sly.uploadfile.algorithm;

/**
 * Created by fmgao on 2019/9/29.
 */
public class CountDigitOne2 {
    public static void main(String[] args) {
        int a = 27;
        int i = countDigitOne(a);
        System.out.println(i);
    }

    public static int countDigitOne(int n) {
        if (n <= 0) {
            return 0;
        }
        String stringN = n + "";
        int ans = 0;
        while (!stringN.isEmpty()) {
            int tempLen = stringN.length();
            String firstChar = stringN.charAt(0) + "";
            if (Integer.parseInt(firstChar) >= 2) {
                ans += 1 * Math.pow(10, tempLen - 1);
            } else if (firstChar.equals("1")) {
                if ("".equals(stringN.substring(1, tempLen))) {
                    ans += 1;
                } else if (!"".equals(stringN.substring(1, tempLen))) {
                    ans += Integer.parseInt(stringN.substring(1, tempLen)) + 1;
                }
            }
            if (tempLen > 1) {
                ans += Integer.parseInt(firstChar) * (tempLen - 1) * Math.pow(10, tempLen - 2);
            }
            stringN = stringN.substring(1);
        }
        return ans;
    }
}


被除数与除数

package com.sly.uploadfile.algorithm;

/**
 * Created by fmgao on 2019/7/9.
 *
 * 给定两个整数,被除数 dividend和除数 divisor。将两数相除,要求不使用乘法、除法和 mod 运算符。
 * 返回被除数 dividend除以除数 divisor得到的商。
 */
public class Divide01 {
    public static int divide(int dividend, int divisor) {
        if (divisor == 0 || (dividend == Integer.MIN_VALUE && divisor == -1)) {
            return Integer.MAX_VALUE;
        }
        int sign = ((dividend < 0) ^ (divisor < 0)) ? -1 : 1;// 异或运算
        long ms = (long) dividend;
        long ns = (long) divisor;
        ms = Math.abs(ms);
        ns = Math.abs(ns);
        int num = 0;
        while (ms >= ns) {
            long m = ns;
            long n = 1;
            while (ms >= (m << 1)) {
                m <<= 1;
                n <<= 1;

            }
            num += n;
            ms -= m;

        }
        return num * sign;
    }

    public static void main(String[] args) {
        int a = divide(46, 3);
        System.out.println(a);
    }
}

数字异或

package com.sly.uploadfile.algorithm;

import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by fmgao on 2019/6/24.
 * <p>
 * 给定一个字符串 s 和一个非空字符串 p,找到 s 中所有是 p 的字母异位词的子串,返回这些子串的起始索引。
 * <p>
 * 字符串只包含小写英文字母,并且字符串 s 和 p 的长度都不超过 20100。
 * <p>
 * Example 1:
 * <p>
 * Input:
 * s: "cbaebabacd" p: "abc"
 * <p>
 * Output:
 * [0, 6]
 * <p>
 * Explanation:
 * The substring with start index = 0 is "cba", which is an anagram of "abc".
 * The substring with start index = 6 is "bac", which is an anagram of "abc".
 * <p>
 * Example 2:
 * <p>
 * Input:
 * s: "abab" p: "ab"
 * <p>
 * Output:
 * [0, 1, 2]
 * <p>
 * Explanation:
 * The substring with start index = 0 is "ab", which is an anagram of "ab".
 * The substring with start index = 1 is "ba", which is an anagram of "ab".
 * The substring with start index = 2 is "ab", which is an anagram of "ab".
 */
@Slf4j
public class EctopicElementService {
    public static List<Integer> findAnagrams(String s, String p) {
        List<Integer> list = new ArrayList<>();
        int lens = s.length();
        int lenp = p.length();
        if (lens < lenp) {
            return list;
        }
        for (int i = 0; i <= lens - lenp; i++) {
            int[] t = new int[26];
            for (int j = 0; j < lenp; j++) {
                t[s.charAt(i + j) - 'a']++;
                t[p.charAt(j) - 'a']--;
            }
            boolean flag = true;
            for (int j = 0; j < t.length; j++) {
                if (t[j] != 0) {
                    flag = false;
                    break;
                }
            }
            if (flag) {
                list.add(i);
            }
        }
//        log.info("list====" + list);
        return list;
    }

    public static void main(String[] args) {
        List<Integer> anagrams = findAnagrams("cbaebabacd", "abc");
        System.out.println(anagrams);
    }
}

 

括号成对校验

package com.sly.uploadfile.algorithm;

import java.util.Stack;

/**
 * Created by fmgao on 2019/6/28.
 */
public class EffectiveParentheses {
    public static boolean isValid(String s) {
        if (s == "" || s.length() == 0) {
            return true;
        }
        Stack stack = new Stack();
        stack.push(s.charAt(0));
        for (int i = 1; i < s.length(); i++) {
            if (!stack.isEmpty()) {
                if (stack.peek().equals((char) (s.charAt(i) - 1)) || stack.peek().equals((char) (s.charAt(i) - 2))) {
                    stack.pop();
                } else {
                    stack.push(s.charAt(i));
                }
            } else {
                stack.push(s.charAt(i));
            }
        }
        if (stack.isEmpty()) {
            return true;
        }
        return false;
    }

    public static boolean isValid2(String s) {
        Stack<Character> stack = new Stack<>();
        for (int i = 0; i < s.length(); i++) {
            char ch = s.charAt(i);
            if (ch == '(' || ch == '[' || ch == '{') {
                stack.push(ch);
            } else {
                if (stack.isEmpty()) {
                    return false;
                }
                char topChar = stack.pop();
                if (ch == ')' && topChar != '(') {
                    return false;
                } else if (ch == ']' && topChar != '[') {
                    return false;
                } else if (ch == '}' && topChar != '{') {
                    return false;
                }
            }
        }
        return stack.isEmpty();
    }

    public static void main(String[] args) {
        long startTime = System.nanoTime();
        boolean res = isValid("()(){}{}(){}()[][]{}");
        long endTime = System.nanoTime();
        System.out.println(res);
        System.out.println("程序运行时间: " + (endTime - startTime) + "ms");

        long startTime2 = System.nanoTime();
        boolean res2 = isValid2("()(){}{}(){}()[][]{}");
        long endTime2 = System.nanoTime();
        System.out.println(res2);
        System.out.println("程序运行时间: " + (endTime2 - startTime2) + "ms");
    }
}

找俩个子串拼接位置

package com.sly.uploadfile.algorithm;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * Created by fmgao on 2019/7/3.
 */
public class FindSonChars {

    public static void main(String[] args) {
        String s = "barfoothefoobarman";
        String[] words = {"foo", "bar"};
        FindSonChars findSonChars = new FindSonChars();
        List<Integer> list = findSonChars.findSubstring(s, words);
        for (Integer a : list) {
            System.out.println(a);
        }

    }

    /**
     * 1、 字符串和数组都是空  就return 空数组
     * 2、
     *
     * @param s
     * @param words
     * @return
     */
    public List<Integer> findSubstring(String s, String[] words) {
        List<Integer> result = new ArrayList<Integer>();
        // 如果s,或者是words为空,那么也返回一个空的列表
        if (s.length() == 0 || s == null || words.length == 0 || words == null) {
            return result;

        }
        int size = words[0].length(), length = words.length;
        // 把字符串数组中的的字符串全部插入HashMap中
        HashMap<String, Integer> map = generate(words);
        // 窗口的不同的起点,有size个不同的起点
        for (int i = 0; i < size; i++) {
            HashMap<String, Integer> window = new HashMap<>();  // 一个滑动的窗口
            int left, right;
            left = right = i;
            while (right <= s.length() - size && left <= s.length() - length * size) {
                String word = s.substring(right, right + size);
                incr(window, word);
                if (!map.containsKey(word)) {
                    window.clear();
                    right += size;
                    left = right;
                    continue;
                }
                while (window.get(word) > map.get(word)) {
                    String w = s.substring(left, left + size);
                    decr(window, w);
                    left += size;
                }
                right += size;
                if (right - left == size * length) {
                    result.add(left);
                }
            }
        }
        return result;

    }

    private HashMap<String, Integer> generate(String[] strs) {
        HashMap<String, Integer> map = new HashMap<>();
        for (String str : strs) {
            incr(map, str);
        }
        return map;
    }

    private void incr(HashMap<String, Integer> map, String str) {
        map.put(str, map.getOrDefault(str, 0) + 1);
    }

    private void decr(HashMap<String, Integer> map, String str) {
        Integer num = map.get(str);
        if (num <= 1) {
            map.remove(str);
        } else {
            map.put(str, num - 1);
        }
    }
}

二分查找升级版

package com.sly.uploadfile.algorithm;

/**
 * Created by fmgao on 2019/11/19.
 * <p>
 * 力扣算法】34-在排序数组中查找元素的第一个和最后一个位置
 * 给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。
 * <p>
 * 你的算法时间复杂度必须是 O(log n) 级别。
 * <p>
 * 如果数组中不存在目标值,返回 [-1, -1]。
 * <p>
 * 示例 1:
 * 输入: nums = [5,7,7,8,8,10], target = 8
 * 输出: [3,4]
 * 示例 2:
 * 输入: nums = [5,7,7,8,8,10], target = 6
 * 输出: [-1,-1]
 */
public class FirstLastSortArray {

    public static void main(String[] args) {
        int[] nums = {5, 7, 8, 8, 8, 10};
        int target = 8;
        int[] ints = searchSort2(nums, target);
        for (int i : ints) {
            System.out.println(i);
        }
    }

    /**
     * 二分查找的升级版。以searchBegin为例,
     * <p>
     * 当nums[mid]>target时,向左查找,
     * 当nums[mid]=targe时,向左查找。
     * 这样所有情况下,范围都会缩小,直到 l == r 为止,这时如果 该位置里的数 == target,则返回该位置,否则返回-1。
     * <p>
     * searchEnd同理
     *
     * @param nums
     * @param target
     * @return
     */
    public static int[] searchSort2(int[] nums, int target) {
        if (nums == null || nums.length == 0) {
            return new int[]{-1, -1};
        }
        int l = 0, r = nums.length;
        int mid = (l + r) / 2;
        int p = -1;
        while (l < r) {
            // 中间
            if (nums[mid] == target) {
                p = mid;
                break;
            }
            // target 在左边
            if (nums[mid] > target) {
                if (r == mid) break;
                r = mid;
                mid = (l + r) / 2;
            } else {
                // 在右边
                if (l == mid) break;
                l = mid;
                mid = (l + r) / 2;
            }
        }
        if (p == -1) {
            return new int[]{-1, -1};
        } else {
            int a = p, b = p;
            while (a > 0 && nums[a - 1] == target) a--;
            while (b < nums.length - 1 && nums[b + 1] == target) b++;
            return new int[]{a, b};
        }
    }
}

 

posted on 2020-06-20 16:22  风-fmgao  阅读(259)  评论(0编辑  收藏  举报