Finding longest substring containing k distinct characters
//use set to keep track of distinct characters
Set&lt;Integer&gt; set=new TreeSet&lt;&gt;();


Use spaces, they're free. According to conventions, there should be spaces around each operator. If you want to use them more sparingly, it's your choice, but think about how they separate things. You code looks like composed of three things

Set&lt;Integer&gt; &nbsp; set=new &nbsp; TreeSet&lt;&gt;();

which is rather confusing.

You write "keep track of distinct characters" and declare Set&lt;Integer&gt;. Why not Set&lt;Character&gt;?

Don't use TreeSet unless you need it. HashSet is faster.

Don't call it set, when you can call it e.g. foundCharacters.



char arr[] = str.toCharArray();


Naming.

while(i&lt;len &amp;&amp; j&lt;len){


Spacing. Always prefer "for" loops as they're much clearer. They also allow you to declare variables in a smaller scope. I'd go for

for (int i=0, j=0; i&lt;len &amp;&amp; j&lt;len; ++j) ...


(add spaces to adhere to conventions), but you're modifying j somewhere in the middle (which is unexpected with a "for" loop). So feel free to stick with "while".



        int substrLen=Math.abs(i-j);


This looks like you lost track of what your variables do. I guess, j&gt;=i always holds, but you should know. You may want to call them start and end.

        int substrLen = Math.abs(i-(j+1));


This makes me suspect. Why do you need a different expression for computing the same thing?

Optimizations


  How can I tweak my logic to improve running time for large strings?


What the problem? You run through the string until you find out that they're too many characters. Then you throw away all information collected so far and start over at the next index. This implies a complexity of \$O(n^2)\$, which is way too slow for \$n=10^6\$.

When you find out that you collected too many distinct characters, you could move the start index until their number gets smaller again. For this, a Set is insufficient, as you have to know, when you get rid of the last occurrence of a given character.

So instead of remembering what characters you ran across, you need to count their occurrences. A Map&lt;Character, Integer&gt; would do. Guava Multiset&lt;Character&gt; would be even better as a multiset is just like a set but allowing duplicates.

But the best solution is an array. As there are just \$2^{16}\$ characters (let's ignore surrogates), you can keep track of them in new int[Character.MAX_VALUE+1]. This gives you a nice speed bonus of maybe factor 10 (it's just a bonus, it would not help you with the quadratic complexity and it's most probably not needed with the new algorithm).



Just a snippet to get you started:

private int distinctChars;
private int[] counts = new int[Character.MAX_VALUE+1];

private void addCharacter(char c) {
    if (counts[c] == 0) {
        distinctChars++;
    }
    counts[c]++;
}

private void removeCharacter(char c) {...}

public int maximumLength(String str, int limit) {
     ...
     for (int i=0, j=0; j&lt;len; ) {
         if (distinctChars &lt;= limit) {
             max = Math.max(max, j-i);
             addCharacter(str[j++]);
         } else {
             removeCharacter(str[i++]);
         }
     }
     ...
}